2 MiddleMan filtering proxy server
3 Copyright (C) 2002 Jason McLaughlin
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <sys/types.h>
29 extern COOKIE_LIST *cookie_list;
32 load <header> section of xml_list into the header_list structure
34 HEADER_LIST *header_load(HEADER_LIST * header_list, XML_LIST * xml_list)
36 HEADER_LIST *tmp_list = header_list;
37 struct HEADER_LIST_LIST *allow = NULL, *deny = NULL, *insert = NULL;
39 if (tmp_list == NULL) {
40 tmp_list = xmalloc(sizeof(HEADER_LIST));
41 tmp_list->allow = NULL;
42 tmp_list->deny = NULL;
43 tmp_list->insert = NULL;
44 tmp_list->policy = POLICY_ALLOW;
46 tmp_list->enabled = TRUE;
48 header_list = tmp_list;
50 pthread_rwlock_init(&tmp_list->lock, NULL);
52 allow = tmp_list->allow;
53 deny = tmp_list->deny;
54 insert = tmp_list->insert;
57 while ((xml_list = xml_section(xml_list, "<header>"))) {
58 XML_LIST_LOOP(xml_list, "<header>") {
59 XML_LIST_CMP(xml_list, "<allow>") {
60 allow = header_ll_new(allow);
61 allow->id = header_list->id++;
63 if (tmp_list->allow == NULL)
64 tmp_list->allow = allow;
65 XML_LIST_LOOP(xml_list, "<allow>") {
66 XML_LIST_CMP(xml_list, "<enabled>") {
67 xml_list = xml_list->next;
68 if (xml_list->type == XML_VALUE) {
69 if (!strcasecmp(xml_list->item, "false"))
70 allow->enabled = FALSE;
72 allow->enabled = TRUE;
75 XML_LIST_CMP(xml_list, "<comment>") {
76 xml_list = xml_list->next;
77 if (xml_list->type == XML_VALUE)
78 header_ll_insert(allow, xml_list->item, NULL, NULL, NULL);
80 XML_LIST_CMP(xml_list, "<type>") {
81 xml_list = xml_list->next;
82 if (xml_list->type == XML_VALUE)
83 header_ll_insert(allow, NULL, xml_list->item, NULL, NULL);
85 XML_LIST_CMP(xml_list, "<value>") {
86 xml_list = xml_list->next;
87 if (xml_list->type == XML_VALUE)
88 header_ll_insert(allow, NULL, NULL, xml_list->item, NULL);
90 XML_LIST_CMP(xml_list, "<host>") {
91 xml_list = xml_list->next;
92 if (xml_list->type == XML_VALUE)
93 header_ll_insert(allow, NULL, NULL, NULL, xml_list->item);
98 XML_LIST_CMP(xml_list, "<deny>") {
99 deny = header_ll_new(deny);
100 deny->id = header_list->id++;
102 if (tmp_list->deny == NULL)
103 tmp_list->deny = deny;
104 XML_LIST_LOOP(xml_list, "<deny>") {
105 XML_LIST_CMP(xml_list, "<enabled>") {
106 xml_list = xml_list->next;
107 if (xml_list->type == XML_VALUE) {
108 if (!strcasecmp(xml_list->item, "false"))
109 deny->enabled = FALSE;
111 deny->enabled = TRUE;
114 XML_LIST_CMP(xml_list, "<comment>") {
115 xml_list = xml_list->next;
116 if (xml_list->type == XML_VALUE)
117 header_ll_insert(deny, xml_list->item, NULL, NULL, NULL);
119 XML_LIST_CMP(xml_list, "<type>") {
120 xml_list = xml_list->next;
121 if (xml_list->type == XML_VALUE)
122 header_ll_insert(deny, NULL, xml_list->item, NULL, NULL);
124 XML_LIST_CMP(xml_list, "<value>") {
125 xml_list = xml_list->next;
126 if (xml_list->type == XML_VALUE)
127 header_ll_insert(deny, NULL, NULL, xml_list->item, NULL);
129 XML_LIST_CMP(xml_list, "<host>") {
130 xml_list = xml_list->next;
131 if (xml_list->type == XML_VALUE)
132 header_ll_insert(deny, NULL, NULL, NULL, xml_list->item);
136 XML_LIST_CMP(xml_list, "<insert>") {
137 insert = header_ll_new(insert);
138 insert->id = header_list->id++;
140 if (tmp_list->insert == NULL)
141 tmp_list->insert = insert;
142 XML_LIST_LOOP(xml_list, "<insert>") {
143 XML_LIST_CMP(xml_list, "<enabled>") {
144 xml_list = xml_list->next;
145 if (xml_list->type == XML_VALUE) {
146 if (!strcasecmp(xml_list->item, "false"))
147 insert->enabled = FALSE;
149 insert->enabled = TRUE;
152 XML_LIST_CMP(xml_list, "<comment>") {
153 xml_list = xml_list->next;
154 if (xml_list->type == XML_VALUE)
155 header_ll_insert(insert, xml_list->item, NULL, NULL, NULL);
157 XML_LIST_CMP(xml_list, "<type>") {
158 xml_list = xml_list->next;
159 if (xml_list->type == XML_VALUE)
160 header_ll_insert(insert, NULL, xml_list->item, NULL, NULL);
162 XML_LIST_CMP(xml_list, "<value>") {
163 xml_list = xml_list->next;
164 if (xml_list->type == XML_VALUE)
165 header_ll_insert(insert, NULL, NULL, xml_list->item, NULL);
167 XML_LIST_CMP(xml_list, "<host>") {
168 xml_list = xml_list->next;
169 if (xml_list->type == XML_VALUE)
170 header_ll_insert(insert, NULL, NULL, NULL, xml_list->item);
174 XML_LIST_CMP(xml_list, "<policy>") {
175 xml_list = xml_list->next;
176 if (xml_list->type == XML_VALUE) {
177 if (!strcasecmp(xml_list->item, "allow"))
178 tmp_list->policy = POLICY_ALLOW;
179 else if (!strcasecmp(xml_list->item, "deny"))
180 tmp_list->policy = POLICY_DENY;
183 XML_LIST_CMP(xml_list, "<enabled>") {
184 xml_list = xml_list->next;
185 if (xml_list->type == XML_VALUE) {
186 if (!strcasecmp(xml_list->item, "false"))
187 tmp_list->enabled = FALSE;
189 tmp_list->enabled = TRUE;
198 XML_LIST *header_xml(HEADER_LIST * header_list, XML_LIST * xml_list)
202 struct HEADER_LIST_LIST *hl = NULL;
204 if (header_list == NULL)
207 pthread_rwlock_rdlock(&header_list->lock);
209 xml_list = xml_list_add(xml_list, "<header>", XML_TAG);
211 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
212 xml_list = xml_list_add(xml_list, (header_list->enabled == TRUE) ? "true" : "false", XML_VALUE);
213 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
215 xml_list = xml_list_add(xml_list, "<policy>", XML_TAG);
216 xml_list = xml_list_add(xml_list, (header_list->policy == POLICY_ALLOW) ? "allow" : "deny", XML_VALUE);
217 xml_list = xml_list_add(xml_list, "</policy>", XML_TAG);
219 for (i = 0; i < 3; i++) {
222 hl = header_list->allow;
225 hl = header_list->deny;
228 hl = header_list->insert;
232 for (; hl; hl = hl->next) {
233 xml_list = xml_list_add(xml_list, (i == 0) ? "<allow>" : (i == 1) ? "<deny>" : "<insert>", XML_TAG);
235 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
236 xml_list = xml_list_add(xml_list, (hl->enabled == TRUE) ? "true" : "false", XML_VALUE);
237 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
239 if (hl->comment != NULL) {
240 xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
241 ptr = string_to_xml(hl->comment);
242 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
244 xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
247 if (hl->type != NULL) {
248 xml_list = xml_list_add(xml_list, "<type>", XML_TAG);
249 ptr = string_to_xml(hl->type);
250 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
252 xml_list = xml_list_add(xml_list, "</type>", XML_TAG);
255 if (hl->value != NULL) {
256 xml_list = xml_list_add(xml_list, "<value>", XML_TAG);
257 ptr = string_to_xml(hl->value);
258 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
260 xml_list = xml_list_add(xml_list, "</value>", XML_TAG);
263 if (hl->host != NULL) {
264 xml_list = xml_list_add(xml_list, "<host>", XML_TAG);
265 ptr = string_to_xml(hl->host);
266 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
268 xml_list = xml_list_add(xml_list, "</host>", XML_TAG);
271 xml_list = xml_list_add(xml_list, (i == 0) ? "</allow>" : (i == 1) ? "</deny>" : "</insert>", XML_TAG);
275 xml_list = xml_list_add(xml_list, "</header>", XML_TAG);
277 pthread_rwlock_unlock(&header_list->lock);
283 free memory used by HEADER_LIST linked list
285 void header_free(HEADER_LIST * header_list)
290 header_ll_free(header_list->allow);
291 header_ll_free(header_list->deny);
292 header_ll_free(header_list->insert);
294 pthread_rwlock_destroy(&header_list->lock);
299 void header_ll_free(struct HEADER_LIST_LIST *hl)
301 struct HEADER_LIST_LIST *tmp;
312 FREE_AND_NULL(hl->comment);
313 FREE_AND_NULL(hl->type);
314 FREE_AND_NULL(hl->value);
315 FREE_AND_NULL(hl->host);
322 void header_ll_insert(struct HEADER_LIST_LIST *x, char *a, char *b, char *c, char *d)
325 FREE_AND_NULL(x->comment);
328 x->comment = xstrdup(a);
333 FREE_AND_NULL(x->type);
336 x->type = xstrdup(b);
337 x->te = reg_compile(b, REGFLAGS);
344 FREE_AND_NULL(x->value);
347 x->value = xstrdup(c);
348 x->ve = reg_compile(c, REGFLAGS);
355 FREE_AND_NULL(x->host);
358 x->host = xstrdup(d);
359 x->he = reg_compile(d, REGFLAGS);
366 struct HEADER_LIST_LIST *header_ll_new(struct HEADER_LIST_LIST *x)
369 x = xmalloc(sizeof(struct HEADER_LIST_LIST));
372 while (x->next != NULL)
374 x->next = xmalloc(sizeof(struct HEADER_LIST_LIST));
392 struct HEADER_LIST_LIST *header_ll_delete(struct HEADER_LIST_LIST *x)
394 struct HEADER_LIST_LIST *start = x;
396 while (start->prev != NULL)
400 x->next->prev = x->prev;
402 x->prev->next = x->next;
410 FREE_AND_NULL(x->comment);
411 FREE_AND_NULL(x->type);
412 FREE_AND_NULL(x->value);
413 FREE_AND_NULL(x->host);
420 struct HTTP_HEADER_LIST *header_list_insert(struct HTTP_HEADER_LIST *x, char *a, char *b)
423 x = xmalloc(sizeof(struct HTTP_HEADER_LIST));
425 while (x->next != NULL)
427 x->next = xmalloc(sizeof(struct HTTP_HEADER_LIST));
431 x->type = xstrdup(a);
432 x->value = xstrdup(b);
437 HEADER *http_header_parse_response(char *s)
440 char version[10], code[10];
443 header = header_new();
445 header->type = HTTP_RESP;
447 x = sscanf(s, "%10s %10s", version, code);
451 if (!strcasecmp(version, "HTTP/1.1"))
452 header->version = HTTP_HTTP11;
454 header->version = HTTP_HTTP10;
456 header->code = atoi(code);
457 if (header->code <= 0) goto error;
459 http_header_list_parse(header, s);
464 http_header_free(header);
468 HEADER *http_header_parse_request(char *s)
472 char buf[8096], method[24], version[10];
474 struct url_command_t **url_command;
476 /* parse first line */
477 /* version can be left out, i.e. "GET /" */
478 x = sscanf(s, "%24s %4096s %10s", method, buf, version);
482 header = header_new();
484 if (!strcasecmp(method, "CONNECT"))
485 header->type = HTTP_CONNECT;
486 else if (buf[0] == '/')
487 header->type = HTTP_REQUEST;
489 header->type = HTTP_PROXY;
491 if (x == 3 && !strcasecmp(version, "HTTP/1.1"))
492 header->version = HTTP_HTTP11;
494 header->version = HTTP_HTTP10;
497 if (header->type != HTTP_REQUEST) {
500 /* find : in http:// */
501 if (header->type != HTTP_CONNECT) {
502 ptr = strchr(buf, ':');
503 if (ptr == NULL) goto error;
507 header->proto = xstrdup(buf);
512 strcpy(buf, &ptr[2]);
515 /* find beginning of file */
516 ptr = strchr(buf, '/');
518 header->file = xstrdup(ptr);
522 /* strip out username:password if it exists, we won't need it */
523 ptr = strchr(buf, '@');
525 strcpy(buf, &ptr[1]);
528 ptr = strchr(buf, ':');
530 header->port = atoi(&ptr[1]);
533 header->port = (header->type == HTTP_CONNECT) ? 443 : 80;
535 header->host = url_decode(buf, strlen(buf));
539 header->file = xstrdup(buf);
542 if (header->file == NULL) header->file = xstrdup("/");
543 header->method = xstrdup(method);
545 http_header_list_parse(header, s);
547 if (header->type != HTTP_REQUEST)
548 header->url_command = url_command_parse(header->host);
550 ptr2 = strchr(&header->file[1], '/');
552 /* take url command from beginning of file if this is an http request */
553 ptr = url_decode(&header->file[1], ptr2 - header->file - 1);
554 header->url_command = url_command_parse(ptr);
557 if (header->url_command != NULL) {
558 strcpy(header->file, ptr2);
560 header->file = xrealloc(header->file, strlen(header->file) + 1);
565 if (header->referer != NULL) {
566 /* get url command from Referer header sent by browser */
567 ptr2 = strstr(header->referer, "://");
571 ptr2 = header->referer;
573 ptr = url_decode(ptr2, strlen(ptr2));
575 url_command = url_command_parse(ptr);
577 if (url_command != NULL) {
578 /* get rid of URL command from Referer string */
579 /* yes.. I know, it's slightly broken... I doubt many sites are THAT pedantic though */
580 xfree(header->referer);
582 ptr2 = url_encode(ptr, strlen(ptr));
583 snprintf(buf, sizeof(buf), "http://%s", ptr2);
586 header->referer = xstrdup(buf);
588 /* this all needs to be done even if we've already got a url command from the URL
589 to get rid of the URL command from the Referer URL */
590 if (header->url_command == NULL)
591 header->url_command = url_command;
593 url_command_free(url_command);
602 http_header_free(header);
606 void http_header_list_parse(HEADER * header, char *s)
608 char *ptr, *lptr, *eolptr, buf[8096];
609 struct HTTP_HEADER_LIST *header_list = NULL;
611 /* iterate through each header, grab useful header values and put them all into a linked list */
612 lptr = strchr(s, '\n');
613 while (lptr != NULL) {
616 eolptr = strchr(lptr, '\n');
618 s_strncpy(buf, lptr, sizeof(buf));
622 ptr = strchr(buf, ':');
624 if (ptr != NULL && ptr[1] != '\0') {
628 if (header->content_length == -1 && !strcasecmp(buf, "Content-length"))
629 header->content_length = atoi(ptr);
630 else if (!header->chunked && !strcasecmp(buf, "Transfer-Encoding") && !strcasecmp(ptr, "chunked"))
631 header->chunked = TRUE;
632 else if (!header->content_type && !strcasecmp(buf, "Content-Type"))
633 header->content_type = xstrdup(ptr);
634 else if (!header->content_encoding && !strcasecmp(buf, "Content-Encoding"))
635 header->content_encoding = xstrdup(ptr);
636 else if (!header->accept_encoding && !strcasecmp(buf, "Accept-Encoding"))
637 header->accept_encoding = xstrdup(ptr);
638 else if (!header->location && !strcasecmp(buf, "Location"))
639 header->location = xstrdup(ptr);
640 else if (!header->host_header && !strcasecmp(buf, "Host"))
641 header->host_header = xstrdup(ptr);
642 else if (!header->proxy_authenticate && !strcasecmp(buf, "Proxy-Authenticate"))
643 header->proxy_authenticate = xstrdup(ptr);
644 else if (!header->proxy_authorization && !strcasecmp(buf, "Proxy-Authorization"))
645 header->proxy_authorization = xstrdup(ptr);
646 else if (!header->referer && !strcasecmp(buf, "Referer"))
647 header->referer = xstrdup(ptr);
648 else if (header->keepalive == -1 && !strcasecmp(buf, "Connection")) {
649 /* some browsers send stuff after the keep-alive or close */
650 if (!strncasecmp(ptr, "keep-alive", 10))
651 header->keepalive = TRUE;
652 else if (!strncasecmp(ptr, "close", 5))
653 header->keepalive = FALSE;
654 } else if (header->proxy_keepalive == -1 && !strcasecmp(buf, "Proxy-Connection")) {
655 if (!strncasecmp(ptr, "keep-alive", 10))
656 header->proxy_keepalive = TRUE;
657 else if (!strncasecmp(ptr, "close", 5))
658 header->proxy_keepalive = FALSE;
661 header_list = header_list_insert(header_list, buf, ptr);
663 if (header->header == NULL)
664 header->header = header_list;
667 if (eolptr != NULL && (eolptr[1] == '\r' || eolptr[1] == '\n'))
675 free memory used by HEADER structure
677 void http_header_free(HEADER * header)
682 http_header_list_free(header->header);
683 http_header_list_free(header->header_filtered);
685 FREE_AND_NULL(header->method);
686 FREE_AND_NULL(header->proto);
687 FREE_AND_NULL(header->host);
688 FREE_AND_NULL(header->file);
689 FREE_AND_NULL(header->content_type);
690 FREE_AND_NULL(header->content_encoding);
691 FREE_AND_NULL(header->accept_encoding);
692 FREE_AND_NULL(header->referer);
693 FREE_AND_NULL(header->location);
694 FREE_AND_NULL(header->host_header);
695 FREE_AND_NULL(header->proxy_authenticate);
696 FREE_AND_NULL(header->proxy_authorization);
698 if (header->url_command != NULL)
699 url_command_free(header->url_command);
704 void http_header_list_free(struct HTTP_HEADER_LIST *header_list)
706 struct HTTP_HEADER_LIST *tmp_list;
708 while (header_list != NULL) {
709 tmp_list = header_list->next;
711 if (header_list->type != NULL)
712 xfree(header_list->type);
713 if (header_list->value != NULL)
714 xfree(header_list->value);
718 header_list = tmp_list;
722 struct HTTP_HEADER_LIST *http_header_list_dup(struct HTTP_HEADER_LIST *header_list)
724 struct HTTP_HEADER_LIST *ret = NULL;
726 for (; header_list; header_list = header_list->next)
727 ret = header_list_insert(ret, header_list->type, header_list->value);
733 filter header list according to rules set in the XML config, return a new list
734 containing only headers for which no deny rule matched
736 struct HTTP_HEADER_LIST *header_filter(HEADER_LIST * header_list, CONNECTION * connection)
738 int action = FALSE, result = TRUE, i, ret;
739 struct HEADER_LIST_LIST *current;
740 struct HTTP_HEADER_LIST *http_header_list, *new_list = NULL, *start = NULL;
742 if (connection->bypass & FEATURE_HEADER)
745 pthread_rwlock_rdlock(&header_list->lock);
747 if (header_list->enabled == FALSE) {
748 pthread_rwlock_unlock(&header_list->lock);
753 http_header_list = connection->header->header;
755 while (http_header_list != NULL) {
756 for (i = 0; i < 2; i++) {
758 if (header_list->policy == POLICY_ALLOW) {
759 current = header_list->deny;
763 current = header_list->allow;
767 } else if (result == action) {
768 if (header_list->policy == POLICY_ALLOW) {
769 current = header_list->allow;
772 current = header_list->deny;
778 for (; current != NULL; current = current->next) {
779 if (current->enabled == FALSE)
782 if (current->te != NULL) {
783 ret = reg_exec(current->te, http_header_list->type);
788 if (current->ve != NULL) {
789 ret = reg_exec(current->ve, http_header_list->value);
794 if (current->he != NULL) {
795 ret = reg_exec(current->he, connection->header->host);
805 if (result == TRUE) {
806 new_list = header_list_insert(new_list, http_header_list->type, http_header_list->value);
810 putlog(MMLOG_HEADER, "removed %s: %s", http_header_list->type, http_header_list->value);
812 http_header_list = http_header_list->next;
815 current = header_list->insert;
817 for (; current != NULL; current = current->next) {
818 if (current->enabled == FALSE)
821 if (current->he != NULL) {
822 ret = reg_exec(current->he, connection->header->host);
827 if (current->type != NULL && current->value != NULL) {
828 new_list = header_list_insert(new_list, current->type, current->value);
829 putlog(MMLOG_HEADER, "added %s: %s", current->type, current->value);
833 pthread_rwlock_unlock(&header_list->lock);
839 retrieve header from browser or server
841 char *header_get(CONNECTION * connection, int flags, int timeout)
843 int x, pos = 0, first = FALSE;
845 struct pollfd pfd[2];
846 SOCKET *sock1, *sock2;
847 time_t start = time(NULL), now;
849 sock1 = (flags == SERVER) ? connection->server : connection->client;
850 sock2 = (flags == SERVER) ? connection->client : connection->server;
852 pfd[0].fd = sock1->fd;
853 pfd[0].events = POLLIN;
856 pfd[1].fd = sock2->fd;
857 pfd[1].events = POLLIN;
864 if (now - start >= timeout)
867 x = p_poll(pfd, (sock2 != NULL) ? 2 : 1, (sock1->inbuf_len != 0) ? 0 : (timeout - (now - start)) * 1000);
869 if (sock1->inbuf_len != 0 || pfd[0].revents & POLLIN) {
870 x = sock_getline(sock1, &buf[pos], sizeof(buf) - pos - 1);
874 if (buf[pos] == '\n' || buf[pos] == '\r' || pos == sizeof(buf) - 1) {
875 /* blank line or buffer size limit reached */
877 /* ignore leading blanklines, this will resolve some issues
878 with non-compliant browsers */
879 if (first == TRUE || pos == sizeof(buf) - 1) {
887 } else if (pfd[0].revents & (POLLHUP | POLLERR))
890 if (pfd[1].revents & POLLIN) {
891 x = sock_read(sock2, NULL, -1);
894 /* the server may disconnect (or already be disconnected)
895 while reading client header */
896 if (flags == CLIENT) {
897 sock_close(connection->server);
898 connection->server = NULL;
904 } else if (pfd[1].revents & (POLLHUP | POLLERR))
912 send formatted HTTP header to browser or website without unwanted headers and blocked cookies
914 void header_send(HEADER * header, CONNECTION * connection, int which, int flags)
917 struct HTTP_HEADER_LIST *http_header_list;
920 sock = (which == SERVER) ? connection->server : connection->client;
921 /* have sock_write buffer everything and write it all at once */
924 http_header_list = (header->header_filtered != NULL) ? header->header_filtered : header->header;
926 if (header->type == HTTP_RESP)
927 putsock(sock, "HTTP/1.1 %d %s\r\n", header->code, code_to_error(header->code));
929 if (flags == HEADER_DIRECT)
930 putsock(sock, "%s %s HTTP/1.1\r\n", header->method, header->file);
932 /* this is going to another proxy */
933 if (header->type == HTTP_CONNECT)
934 putsock(sock, "CONNECT %s:%d HTTP/1.1\r\n", header->host, header->port);
936 putsock(sock, "%s http://%s:%d%s HTTP/1.1\r\n", header->method, header->host, header->port, header->file);
940 while (http_header_list != NULL) {
941 if (!strncasecmp(http_header_list->type, "Set-Cookie", 10) || !strncasecmp(http_header_list->type, "Cookie", 6)) {
942 send = cookie_check(cookie_list, (header->type == HTTP_RESP) ? COOKIE_IN : COOKIE_OUT, connection);
944 if (header->type == HTTP_RESP)
945 putlog(MMLOG_COOKIE, "blocked incoming from %s", header->host);
947 putlog(MMLOG_COOKIE, "blocked outgoing to %s", header->host);
949 } else if (bad_header(http_header_list->type, flags))
953 putsock(sock, "%s: %s\r\n", http_header_list->type, http_header_list->value);
957 http_header_list = http_header_list->next;
960 /* content type could have been changed if the content was parsed with an external program,
961 therefore we need to send our own content-type header, not the one the site sent */
962 if (header->content_type != NULL && strcmp(header->content_type, ""))
963 putsock(sock, "Content-type: %s\r\n", header->content_type);
965 if (header->content_length != -1)
966 putsock(sock, "Content-Length: %d\r\n", header->content_length);
969 putsock(sock, "Transfer-Encoding: chunked\r\n");
974 putsock(sock, "Proxy-Connection: keep-alive\r\n");
976 /* this doesn't really need to be sent with every request.. but what's the harm? :) */
977 if (connection->proxy_auth != NULL)
978 putsock(sock, "Proxy-Authorization: %s\r\n", connection->proxy_auth);
980 /* if gzip encoding is not supported, not sending an Accept-Encoding header at all
981 fixes some issues with buggy versions of PHP */
983 putsock(sock, "Accept-Encoding: %s\r\n", header->accept_encoding);
984 #endif /* HAVE_ZLIB */
985 /* we need to pass our own Host: header, since the one the browser sent would be wrong
986 if we're doing a redirect
987 note: some servers have problems interpreting the port field, omit it if it's 80 */
988 if (header->port == 80)
989 putsock(sock, "Host: %s\r\n", header->host);
991 putsock(sock, "Host: %s:%d\r\n", header->host, header->port);
993 putsock(sock, "Connection: keep-alive\r\n");
996 if (header->location != NULL)
997 putsock(sock, "Location: %s\r\n", header->location);
999 if (header->proxy_authenticate != NULL)
1000 putsock(sock, "Proxy-Authenticate: %s\r\n", header->proxy_authenticate);
1002 if (header->content_encoding != NULL)
1003 putsock(sock, "Content-Encoding: %s\r\n", header->content_encoding);
1005 putsock(sock, "Connection: %s\r\n", (connection->keepalive_client) ? "keep-alive" : "close");
1006 putsock(sock, "Proxy-Connection: %s\r\n", (connection->keepalive_client) ? "keep-alive" : "close");
1010 putsock(sock, "\r\n");
1016 return TRUE if header type isn't allowed to be passed, otherwise return FALSE
1018 int bad_header(char *type, int flags)
1022 if (!strcasecmp(type, "Connection") || !strncasecmp(type, "Proxy-", 6) || !strcasecmp(type, "Location") || !strncasecmp(type, "Content-", 8) || !strcasecmp(type, "Transfer-Encoding"))
1026 case HEADER_FORWARD:
1027 if (!strcasecmp(type, "Host") || !strncasecmp(type, "Proxy-", 6) || !strncasecmp(type, "Content-", 8) || !strcasecmp(type, "Accept-Encoding") || !strcasecmp(type, "connection") || !strcasecmp(type, "keep-alive") || !strcasecmp(type, "TE") || !strcasecmp(type, "expect"))
1035 return an emtpy HEADER * struct
1037 HEADER *header_new()
1041 header = xmalloc(sizeof(HEADER));
1043 header->proto = NULL;
1044 header->host = NULL;
1045 header->file = NULL;
1046 header->method = NULL;
1047 header->version = 0;
1051 header->header = NULL;
1052 header->header_filtered = NULL;
1053 header->content_length = -1;
1054 header->referer = NULL;
1055 header->chunked = FALSE;
1056 /* these need to be initialized as -1, since what we do when the client or server doesn't send a Connection:
1057 header is determined by the protocol version */
1058 header->keepalive = -1;
1059 header->proxy_keepalive = -1;
1060 header->content_type = NULL;
1061 header->content_encoding = NULL;
1062 header->accept_encoding = NULL;
1063 header->location = NULL;
1064 header->url_command = NULL;
1065 header->host_header = NULL;
1066 header->proxy_authenticate = NULL;
1067 header->proxy_authorization = NULL;
1071 HEADER *http_header_dup(HEADER * h)
1075 header = xmalloc(sizeof(HEADER));
1077 header->proto = (h->proto != NULL) ? xstrdup(h->proto) : NULL;
1078 header->host = (h->host != NULL) ? xstrdup(h->host) : NULL;
1079 header->file = (h->file != NULL) ? xstrdup(h->file) : NULL;
1080 header->method = (h->method != NULL) ? xstrdup(h->method) : NULL;
1081 header->version = h->version;
1082 header->code = h->code;
1083 header->type = h->type;
1084 header->port = h->port;
1085 header->header = http_header_list_dup(h->header);
1086 header->header_filtered = http_header_list_dup(h->header_filtered);
1087 header->content_length = h->content_length;
1088 header->chunked = h->chunked;
1089 header->keepalive = h->keepalive;
1090 header->proxy_keepalive = h->proxy_keepalive;
1091 header->content_type = (h->content_type != NULL) ? xstrdup(h->content_type) : NULL;
1092 header->content_encoding = (h->content_encoding != NULL) ? xstrdup(h->content_encoding) : NULL;
1093 header->accept_encoding = (h->accept_encoding != NULL) ? xstrdup(h->accept_encoding) : NULL;
1094 header->location = (h->location != NULL) ? xstrdup(h->location) : NULL;
1095 header->url_command = NULL;
1096 header->host_header = (h->host_header != NULL) ? xstrdup(h->host_header) : NULL;
1097 header->proxy_authenticate = (h->proxy_authenticate != NULL) ? xstrdup(h->proxy_authenticate) : NULL;
1098 header->proxy_authorization = (h->proxy_authorization != NULL) ? xstrdup(h->proxy_authorization) : NULL;
1099 header->referer = (h->referer != NULL) ? xstrdup(h->referer) : NULL;
1105 parse options prefixed to a url, these can be stacked.. i.e. debug..bypass[r]..host.com
1107 struct url_command_t **url_command_parse(char *url)
1110 char *end, *ptr, *ptr2;
1111 struct url_command_t **ret = NULL;
1113 while ((end = strstr(url, ".."))) {
1114 ret = xrealloc(ret, (count + 2) * sizeof(struct url_command_t *));
1115 ret[count] = xmalloc(sizeof(struct url_command_t));
1117 ret[count + 1] = NULL;
1119 ptr = memchr(url, '[', end - url);
1123 ptr2 = memchr(ptr, ']', end - url);
1125 ret[count]->options = xstrndup(&ptr[1], ptr2 - ptr - 1);
1127 ret[count]->options = NULL;
1129 ret[count]->command = xstrndup(url, (ptr != NULL) ? ptr - url : end - url);
1131 strcpy(url, (ptr2 != NULL) ? &ptr2[3] : &end[2]);
1139 char *url_command_create(struct url_command_t **url_command) {
1143 filebuf = filebuf_new();
1145 for (; *url_command; url_command++) {
1146 if ((*url_command)->options != NULL)
1147 filebuf_addf(filebuf, "%s[%s]..", (*url_command)->command, (*url_command)->options);
1149 filebuf_addf(filebuf, "%s..", (*url_command)->command);
1152 filebuf_add(filebuf, "", 1);
1154 filebuf_shorten(filebuf);
1155 ret = filebuf->data;
1156 filebuf->data = NULL;
1158 filebuf_free(filebuf);
1163 void url_command_free(struct url_command_t **url_command)
1165 struct url_command_t **tmp = url_command;
1167 while (*tmp != NULL) {
1168 FREE_AND_NULL((*tmp)->command);
1169 FREE_AND_NULL((*tmp)->options);
1179 /* prefix URL command to a URL */
1180 char *url_command_add(CONNECTION *connection, char *url) {
1181 char *uc, *ptr, buf[8096];
1183 uc = url_command_create(connection->header->url_command);
1186 snprintf(buf, sizeof(buf), "http://%s%s:%d%s", uc, connection->header->host, connection->header->port, url);
1188 ptr = strstr(url, "://");
1189 if ((ptr != NULL && !strncasecmp(url, "http", 4)) || ptr == NULL) {
1195 snprintf(buf, sizeof(buf), "http://%s%s", uc, ptr);
1201 return xstrdup(buf);