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>
28 extern COOKIE_LIST *cookie_list;
31 load <header> section of xml_list into the header_list structure
33 HEADER_LIST *header_load(HEADER_LIST * header_list, XML_LIST * xml_list)
35 HEADER_LIST *tmp_list = header_list;
36 struct HEADER_LIST_LIST *allow = NULL, *deny = NULL, *insert = NULL;
38 if (tmp_list == NULL) {
39 tmp_list = xmalloc(sizeof(HEADER_LIST));
40 tmp_list->allow = NULL;
41 tmp_list->deny = NULL;
42 tmp_list->insert = NULL;
43 tmp_list->policy = POLICY_ALLOW;
45 tmp_list->enabled = TRUE;
47 header_list = tmp_list;
49 pthread_rwlock_init(&tmp_list->lock, NULL);
51 allow = tmp_list->allow;
52 deny = tmp_list->deny;
53 insert = tmp_list->insert;
56 while ((xml_list = xml_section(xml_list, "<header>"))) {
57 XML_LIST_LOOP(xml_list, "<header>") {
58 XML_LIST_CMP(xml_list, "<allow>") {
59 allow = header_ll_new(allow);
60 allow->id = header_list->id++;
62 if (tmp_list->allow == NULL)
63 tmp_list->allow = allow;
64 XML_LIST_LOOP(xml_list, "<allow>") {
65 XML_LIST_CMP(xml_list, "<enabled>") {
66 xml_list = xml_list->next;
67 if (xml_list->type == XML_VALUE) {
68 if (!strcasecmp(xml_list->item, "false"))
69 allow->enabled = FALSE;
71 allow->enabled = TRUE;
74 XML_LIST_CMP(xml_list, "<comment>") {
75 xml_list = xml_list->next;
76 if (xml_list->type == XML_VALUE)
77 header_ll_insert(allow, xml_list->item, NULL, NULL, NULL);
79 XML_LIST_CMP(xml_list, "<type>") {
80 xml_list = xml_list->next;
81 if (xml_list->type == XML_VALUE)
82 header_ll_insert(allow, NULL, xml_list->item, NULL, NULL);
84 XML_LIST_CMP(xml_list, "<value>") {
85 xml_list = xml_list->next;
86 if (xml_list->type == XML_VALUE)
87 header_ll_insert(allow, NULL, NULL, xml_list->item, NULL);
89 XML_LIST_CMP(xml_list, "<host>") {
90 xml_list = xml_list->next;
91 if (xml_list->type == XML_VALUE)
92 header_ll_insert(allow, NULL, NULL, NULL, xml_list->item);
97 XML_LIST_CMP(xml_list, "<deny>") {
98 deny = header_ll_new(deny);
99 deny->id = header_list->id++;
101 if (tmp_list->deny == NULL)
102 tmp_list->deny = deny;
103 XML_LIST_LOOP(xml_list, "<deny>") {
104 XML_LIST_CMP(xml_list, "<enabled>") {
105 xml_list = xml_list->next;
106 if (xml_list->type == XML_VALUE) {
107 if (!strcasecmp(xml_list->item, "false"))
108 deny->enabled = FALSE;
110 deny->enabled = TRUE;
113 XML_LIST_CMP(xml_list, "<comment>") {
114 xml_list = xml_list->next;
115 if (xml_list->type == XML_VALUE)
116 header_ll_insert(deny, xml_list->item, NULL, NULL, NULL);
118 XML_LIST_CMP(xml_list, "<type>") {
119 xml_list = xml_list->next;
120 if (xml_list->type == XML_VALUE)
121 header_ll_insert(deny, NULL, xml_list->item, NULL, NULL);
123 XML_LIST_CMP(xml_list, "<value>") {
124 xml_list = xml_list->next;
125 if (xml_list->type == XML_VALUE)
126 header_ll_insert(deny, NULL, NULL, xml_list->item, NULL);
128 XML_LIST_CMP(xml_list, "<host>") {
129 xml_list = xml_list->next;
130 if (xml_list->type == XML_VALUE)
131 header_ll_insert(deny, NULL, NULL, NULL, xml_list->item);
135 XML_LIST_CMP(xml_list, "<insert>") {
136 insert = header_ll_new(insert);
137 insert->id = header_list->id++;
139 if (tmp_list->insert == NULL)
140 tmp_list->insert = insert;
141 XML_LIST_LOOP(xml_list, "<insert>") {
142 XML_LIST_CMP(xml_list, "<enabled>") {
143 xml_list = xml_list->next;
144 if (xml_list->type == XML_VALUE) {
145 if (!strcasecmp(xml_list->item, "false"))
146 insert->enabled = FALSE;
148 insert->enabled = TRUE;
151 XML_LIST_CMP(xml_list, "<comment>") {
152 xml_list = xml_list->next;
153 if (xml_list->type == XML_VALUE)
154 header_ll_insert(insert, xml_list->item, NULL, NULL, NULL);
156 XML_LIST_CMP(xml_list, "<type>") {
157 xml_list = xml_list->next;
158 if (xml_list->type == XML_VALUE)
159 header_ll_insert(insert, NULL, xml_list->item, NULL, NULL);
161 XML_LIST_CMP(xml_list, "<value>") {
162 xml_list = xml_list->next;
163 if (xml_list->type == XML_VALUE)
164 header_ll_insert(insert, NULL, NULL, xml_list->item, NULL);
166 XML_LIST_CMP(xml_list, "<host>") {
167 xml_list = xml_list->next;
168 if (xml_list->type == XML_VALUE)
169 header_ll_insert(insert, NULL, NULL, NULL, xml_list->item);
173 XML_LIST_CMP(xml_list, "<policy>") {
174 xml_list = xml_list->next;
175 if (xml_list->type == XML_VALUE) {
176 if (!strcasecmp(xml_list->item, "allow"))
177 tmp_list->policy = POLICY_ALLOW;
178 else if (!strcasecmp(xml_list->item, "deny"))
179 tmp_list->policy = POLICY_DENY;
182 XML_LIST_CMP(xml_list, "<enabled>") {
183 xml_list = xml_list->next;
184 if (xml_list->type == XML_VALUE) {
185 if (!strcasecmp(xml_list->item, "false"))
186 tmp_list->enabled = FALSE;
188 tmp_list->enabled = TRUE;
197 XML_LIST *header_xml(HEADER_LIST * header_list, XML_LIST * xml_list)
201 struct HEADER_LIST_LIST *hl = NULL;
203 if (header_list == NULL)
206 pthread_rwlock_rdlock(&header_list->lock);
208 xml_list = xml_list_add(xml_list, "<header>", XML_TAG);
210 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
211 xml_list = xml_list_add(xml_list, (header_list->enabled == TRUE) ? "true" : "false", XML_VALUE);
212 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
214 xml_list = xml_list_add(xml_list, "<policy>", XML_TAG);
215 xml_list = xml_list_add(xml_list, (header_list->policy == POLICY_ALLOW) ? "allow" : "deny", XML_VALUE);
216 xml_list = xml_list_add(xml_list, "</policy>", XML_TAG);
218 for (i = 0; i < 3; i++) {
221 hl = header_list->allow;
224 hl = header_list->deny;
227 hl = header_list->insert;
231 for (; hl; hl = hl->next) {
232 xml_list = xml_list_add(xml_list, (i == 0) ? "<allow>" : (i == 1) ? "<deny>" : "<insert>", XML_TAG);
234 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
235 xml_list = xml_list_add(xml_list, (hl->enabled == TRUE) ? "true" : "false", XML_VALUE);
236 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
238 if (hl->comment != NULL) {
239 xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
240 ptr = string_to_xml(hl->comment);
241 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
243 xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
246 if (hl->type != NULL) {
247 xml_list = xml_list_add(xml_list, "<type>", XML_TAG);
248 ptr = string_to_xml(hl->type);
249 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
251 xml_list = xml_list_add(xml_list, "</type>", XML_TAG);
254 if (hl->value != NULL) {
255 xml_list = xml_list_add(xml_list, "<value>", XML_TAG);
256 ptr = string_to_xml(hl->value);
257 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
259 xml_list = xml_list_add(xml_list, "</value>", XML_TAG);
262 if (hl->host != NULL) {
263 xml_list = xml_list_add(xml_list, "<host>", XML_TAG);
264 ptr = string_to_xml(hl->host);
265 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
267 xml_list = xml_list_add(xml_list, "</host>", XML_TAG);
270 xml_list = xml_list_add(xml_list, (i == 0) ? "</allow>" : (i == 1) ? "</deny>" : "</insert>", XML_TAG);
274 xml_list = xml_list_add(xml_list, "</header>", XML_TAG);
276 pthread_rwlock_unlock(&header_list->lock);
282 free memory used by HEADER_LIST linked list
284 void header_free(HEADER_LIST * header_list)
289 header_ll_free(header_list->allow);
290 header_ll_free(header_list->deny);
291 header_ll_free(header_list->insert);
293 pthread_rwlock_destroy(&header_list->lock);
298 void header_ll_free(struct HEADER_LIST_LIST *hl)
300 struct HEADER_LIST_LIST *tmp;
311 FREE_AND_NULL(hl->comment);
312 FREE_AND_NULL(hl->type);
313 FREE_AND_NULL(hl->value);
314 FREE_AND_NULL(hl->host);
321 void header_ll_insert(struct HEADER_LIST_LIST *x, char *a, char *b, char *c, char *d)
324 FREE_AND_NULL(x->comment);
327 x->comment = xstrdup(a);
332 FREE_AND_NULL(x->type);
335 x->type = xstrdup(b);
336 x->te = reg_compile(b, REGFLAGS);
343 FREE_AND_NULL(x->value);
346 x->value = xstrdup(c);
347 x->ve = reg_compile(c, REGFLAGS);
354 FREE_AND_NULL(x->host);
357 x->host = xstrdup(d);
358 x->he = reg_compile(d, REGFLAGS);
365 struct HEADER_LIST_LIST *header_ll_new(struct HEADER_LIST_LIST *x)
368 x = xmalloc(sizeof(struct HEADER_LIST_LIST));
371 while (x->next != NULL)
373 x->next = xmalloc(sizeof(struct HEADER_LIST_LIST));
391 struct HEADER_LIST_LIST *header_ll_delete(struct HEADER_LIST_LIST *x)
393 struct HEADER_LIST_LIST *start = x;
395 while (start->prev != NULL)
399 x->next->prev = x->prev;
401 x->prev->next = x->next;
409 FREE_AND_NULL(x->comment);
410 FREE_AND_NULL(x->type);
411 FREE_AND_NULL(x->value);
412 FREE_AND_NULL(x->host);
419 struct HTTP_HEADER_LIST *header_list_insert(struct HTTP_HEADER_LIST *x, char *a, char *b)
422 x = xmalloc(sizeof(struct HTTP_HEADER_LIST));
424 while (x->next != NULL)
426 x->next = xmalloc(sizeof(struct HTTP_HEADER_LIST));
430 x->type = xstrdup(a);
431 x->value = xstrdup(b);
436 HEADER *http_header_parse_response(char *s)
439 char version[10], code[10];
442 header = header_new();
444 header->type = HTTP_RESP;
446 x = sscanf(s, "%10s %10s", version, code);
450 if (!strcasecmp(version, "HTTP/1.1"))
451 header->version = HTTP_HTTP11;
453 header->version = HTTP_HTTP10;
455 header->code = atoi(code);
456 if (header->code <= 0) goto error;
458 http_header_list_parse(header, s);
463 http_header_free(header);
467 HEADER *http_header_parse_request(char *s)
471 char buf[8096], method[24], version[10];
473 struct url_command_t **url_command;
475 /* parse first line */
476 /* version can be left out, i.e. "GET /" */
477 x = sscanf(s, "%24s %4096s %10s", method, buf, version);
481 header = header_new();
483 if (!strcasecmp(method, "CONNECT"))
484 header->type = HTTP_CONNECT;
485 else if (buf[0] == '/')
486 header->type = HTTP_REQUEST;
488 header->type = HTTP_PROXY;
490 if (x == 3 && !strcasecmp(version, "HTTP/1.1"))
491 header->version = HTTP_HTTP11;
493 header->version = HTTP_HTTP10;
496 if (header->type != HTTP_REQUEST) {
499 /* find : in http:// */
500 if (header->type != HTTP_CONNECT) {
501 ptr = strchr(buf, ':');
502 if (ptr == NULL) goto error;
506 header->proto = xstrdup(buf);
511 strcpy(buf, &ptr[2]);
514 /* find beginning of file */
515 ptr = strchr(buf, '/');
517 header->file = xstrdup(ptr);
521 /* strip out username:password if it exists, we won't need it */
522 ptr = strchr(buf, '@');
524 strcpy(buf, &ptr[1]);
527 ptr = strchr(buf, ':');
529 header->port = atoi(&ptr[1]);
532 header->port = (header->type == HTTP_CONNECT) ? 443 : 80;
534 header->host = url_decode(buf, strlen(buf));
538 header->file = xstrdup(buf);
541 if (header->file == NULL) header->file = xstrdup("/");
542 header->method = xstrdup(method);
544 http_header_list_parse(header, s);
546 if (header->type != HTTP_REQUEST)
547 header->url_command = url_command_parse(header->host);
549 ptr2 = strchr(&header->file[1], '/');
551 /* take url command from beginning of file if this is an http request */
552 ptr = url_decode(&header->file[1], ptr2 - header->file - 1);
553 header->url_command = url_command_parse(ptr);
556 if (header->url_command != NULL) {
557 strcpy(header->file, ptr2);
559 header->file = xrealloc(header->file, strlen(header->file) + 1);
564 if (header->referer != NULL) {
565 /* get url command from Referer header sent by browser */
566 ptr2 = strstr(header->referer, "://");
570 ptr2 = header->referer;
572 ptr = url_decode(ptr2, strlen(ptr2));
574 url_command = url_command_parse(ptr);
576 if (url_command != NULL) {
577 /* get rid of URL command from Referer string */
578 /* yes.. I know, it's slightly broken... I doubt many sites are THAT pedantic though */
579 xfree(header->referer);
581 ptr2 = url_encode(ptr, strlen(ptr));
582 snprintf(buf, sizeof(buf), "http://%s", ptr2);
585 header->referer = xstrdup(buf);
587 /* this all needs to be done even if we've already got a url command from the URL
588 to get rid of the URL command from the Referer URL */
589 if (header->url_command == NULL)
590 header->url_command = url_command;
592 url_command_free(url_command);
601 http_header_free(header);
605 void http_header_list_parse(HEADER * header, char *s)
607 char *ptr, *lptr, *eolptr, buf[8096];
608 struct HTTP_HEADER_LIST *header_list = NULL;
610 /* iterate through each header, grab useful header values and put them all into a linked list */
611 lptr = strchr(s, '\n');
612 while (lptr != NULL) {
615 eolptr = strchr(lptr, '\n');
617 s_strncpy(buf, lptr, sizeof(buf));
621 ptr = strchr(buf, ':');
623 if (ptr != NULL && ptr[1] != '\0') {
627 if (header->content_length == -1 && !strcasecmp(buf, "Content-length"))
628 header->content_length = atoi(ptr);
629 else if (!header->chunked && !strcasecmp(buf, "Transfer-Encoding") && !strcasecmp(ptr, "chunked"))
630 header->chunked = TRUE;
631 else if (!header->content_type && !strcasecmp(buf, "Content-Type"))
632 header->content_type = xstrdup(ptr);
633 else if (!header->content_encoding && !strcasecmp(buf, "Content-Encoding"))
634 header->content_encoding = xstrdup(ptr);
635 else if (!header->accept_encoding && !strcasecmp(buf, "Accept-Encoding"))
636 header->accept_encoding = xstrdup(ptr);
637 else if (!header->location && !strcasecmp(buf, "Location"))
638 header->location = xstrdup(ptr);
639 else if (!header->host_header && !strcasecmp(buf, "Host"))
640 header->host_header = xstrdup(ptr);
641 else if (!header->proxy_authenticate && !strcasecmp(buf, "Proxy-Authenticate"))
642 header->proxy_authenticate = xstrdup(ptr);
643 else if (!header->proxy_authorization && !strcasecmp(buf, "Proxy-Authorization"))
644 header->proxy_authorization = xstrdup(ptr);
645 else if (!header->referer && !strcasecmp(buf, "Referer"))
646 header->referer = xstrdup(ptr);
647 else if (header->keepalive == -1 && !strcasecmp(buf, "Connection")) {
648 /* some browsers send stuff after the keep-alive or close */
649 if (!strncasecmp(ptr, "keep-alive", 10))
650 header->keepalive = TRUE;
651 else if (!strncasecmp(ptr, "close", 5))
652 header->keepalive = FALSE;
653 } else if (header->proxy_keepalive == -1 && !strcasecmp(buf, "Proxy-Connection")) {
654 if (!strncasecmp(ptr, "keep-alive", 10))
655 header->proxy_keepalive = TRUE;
656 else if (!strncasecmp(ptr, "close", 5))
657 header->proxy_keepalive = FALSE;
660 header_list = header_list_insert(header_list, buf, ptr);
662 if (header->header == NULL)
663 header->header = header_list;
666 if (eolptr != NULL && (eolptr[1] == '\r' || eolptr[1] == '\n'))
674 free memory used by HEADER structure
676 void http_header_free(HEADER * header)
681 http_header_list_free(header->header);
682 http_header_list_free(header->header_filtered);
684 FREE_AND_NULL(header->method);
685 FREE_AND_NULL(header->proto);
686 FREE_AND_NULL(header->host);
687 FREE_AND_NULL(header->file);
688 FREE_AND_NULL(header->content_type);
689 FREE_AND_NULL(header->content_encoding);
690 FREE_AND_NULL(header->accept_encoding);
691 FREE_AND_NULL(header->referer);
692 FREE_AND_NULL(header->location);
693 FREE_AND_NULL(header->host_header);
694 FREE_AND_NULL(header->proxy_authenticate);
695 FREE_AND_NULL(header->proxy_authorization);
697 if (header->url_command != NULL)
698 url_command_free(header->url_command);
703 void http_header_list_free(struct HTTP_HEADER_LIST *header_list)
705 struct HTTP_HEADER_LIST *tmp_list;
707 while (header_list != NULL) {
708 tmp_list = header_list->next;
710 if (header_list->type != NULL)
711 xfree(header_list->type);
712 if (header_list->value != NULL)
713 xfree(header_list->value);
717 header_list = tmp_list;
721 struct HTTP_HEADER_LIST *http_header_list_dup(struct HTTP_HEADER_LIST *header_list)
723 struct HTTP_HEADER_LIST *ret = NULL;
725 for (; header_list; header_list = header_list->next)
726 ret = header_list_insert(ret, header_list->type, header_list->value);
732 filter header list according to rules set in the XML config, return a new list
733 containing only headers for which no deny rule matched
735 struct HTTP_HEADER_LIST *header_filter(HEADER_LIST * header_list, CONNECTION * connection)
737 int action = FALSE, result = TRUE, i, ret;
738 struct HEADER_LIST_LIST *current;
739 struct HTTP_HEADER_LIST *http_header_list, *new_list = NULL, *start = NULL;
741 if (connection->bypass & FEATURE_HEADER)
744 pthread_rwlock_rdlock(&header_list->lock);
746 if (header_list->enabled == FALSE) {
747 pthread_rwlock_unlock(&header_list->lock);
752 http_header_list = connection->header->header;
754 while (http_header_list != NULL) {
755 for (i = 0; i < 2; i++) {
757 if (header_list->policy == POLICY_ALLOW) {
758 current = header_list->deny;
762 current = header_list->allow;
766 } else if (result == action) {
767 if (header_list->policy == POLICY_ALLOW) {
768 current = header_list->allow;
771 current = header_list->deny;
777 for (; current != NULL; current = current->next) {
778 if (current->enabled == FALSE)
781 if (current->te != NULL) {
782 ret = reg_exec(current->te, http_header_list->type);
787 if (current->ve != NULL) {
788 ret = reg_exec(current->ve, http_header_list->value);
793 if (current->he != NULL) {
794 ret = reg_exec(current->he, connection->header->host);
804 if (result == TRUE) {
805 new_list = header_list_insert(new_list, http_header_list->type, http_header_list->value);
809 putlog(MMLOG_HEADER, "removed %s: %s", http_header_list->type, http_header_list->value);
811 http_header_list = http_header_list->next;
814 current = header_list->insert;
816 for (; current != NULL; current = current->next) {
817 if (current->enabled == FALSE)
820 if (current->he != NULL) {
821 ret = reg_exec(current->he, connection->header->host);
826 if (current->type != NULL && current->value != NULL) {
827 new_list = header_list_insert(new_list, current->type, current->value);
828 putlog(MMLOG_HEADER, "added %s: %s", current->type, current->value);
832 pthread_rwlock_unlock(&header_list->lock);
838 retrieve header from browser or server
840 char *header_get(CONNECTION * connection, int flags, int timeout)
842 int x, pos = 0, first = FALSE;
844 struct pollfd pfd[2];
845 SOCKET *sock1, *sock2;
846 time_t start = time(NULL), now;
848 sock1 = (flags == SERVER) ? connection->server : connection->client;
849 sock2 = (flags == SERVER) ? connection->client : connection->server;
851 pfd[0].fd = sock1->fd;
852 pfd[0].events = POLLIN;
855 pfd[1].fd = sock2->fd;
856 pfd[1].events = POLLIN;
863 if (now - start >= timeout)
866 x = p_poll(pfd, (sock2 != NULL) ? 2 : 1, (sock1->inbuf_len != 0) ? 0 : (timeout - (now - start)) * 1000);
868 if (sock1->inbuf_len != 0 || pfd[0].revents & POLLIN) {
869 x = sock_getline(sock1, &buf[pos], sizeof(buf) - pos - 1);
873 if (buf[pos] == '\n' || buf[pos] == '\r' || pos == sizeof(buf) - 1) {
874 /* blank line or buffer size limit reached */
876 /* ignore leading blanklines, this will resolve some issues
877 with non-compliant browsers */
878 if (first == TRUE || pos == sizeof(buf) - 1) {
886 } else if (pfd[0].revents & (POLLHUP | POLLERR))
889 if (pfd[1].revents & POLLIN) {
890 x = sock_read(sock2, NULL, -1);
893 /* the server may disconnect (or already be disconnected)
894 while reading client header */
895 if (flags == CLIENT) {
896 sock_close(connection->server);
897 connection->server = NULL;
903 } else if (pfd[1].revents & (POLLHUP | POLLERR))
911 send formatted HTTP header to browser or website without unwanted headers and blocked cookies
913 void header_send(HEADER * header, CONNECTION * connection, int which, int flags)
916 struct HTTP_HEADER_LIST *http_header_list;
919 sock = (which == SERVER) ? connection->server : connection->client;
920 /* have sock_write buffer everything and write it all at once */
923 http_header_list = (header->header_filtered != NULL) ? header->header_filtered : header->header;
925 if (header->type == HTTP_RESP)
926 putsock(sock, "HTTP/1.1 %d %s\r\n", header->code, code_to_error(header->code));
928 if (flags == HEADER_DIRECT)
929 putsock(sock, "%s %s HTTP/1.1\r\n", header->method, header->file);
931 /* this is going to another proxy */
932 if (header->type == HTTP_CONNECT)
933 putsock(sock, "CONNECT %s:%d HTTP/1.1\r\n", header->host, header->port);
935 putsock(sock, "%s http://%s:%d%s HTTP/1.1\r\n", header->method, header->host, header->port, header->file);
939 while (http_header_list != NULL) {
940 if (!strncasecmp(http_header_list->type, "Set-Cookie", 10) || !strncasecmp(http_header_list->type, "Cookie", 6)) {
941 send = cookie_check(cookie_list, (header->type == HTTP_RESP) ? COOKIE_IN : COOKIE_OUT, connection);
943 if (header->type == HTTP_RESP)
944 putlog(MMLOG_COOKIE, "blocked incoming from %s", header->host);
946 putlog(MMLOG_COOKIE, "blocked outgoing to %s", header->host);
948 } else if (bad_header(http_header_list->type, flags))
952 putsock(sock, "%s: %s\r\n", http_header_list->type, http_header_list->value);
956 http_header_list = http_header_list->next;
959 /* content type could have been changed if the content was parsed with an external program,
960 therefore we need to send our own content-type header, not the one the site sent */
961 if (header->content_type != NULL && strcmp(header->content_type, ""))
962 putsock(sock, "Content-type: %s\r\n", header->content_type);
964 if (header->content_length != -1)
965 putsock(sock, "Content-Length: %d\r\n", header->content_length);
968 putsock(sock, "Transfer-Encoding: chunked\r\n");
973 putsock(sock, "Proxy-Connection: keep-alive\r\n");
975 /* this doesn't really need to be sent with every request.. but what's the harm? :) */
976 if (connection->proxy_auth != NULL)
977 putsock(sock, "Proxy-Authorization: %s\r\n", connection->proxy_auth);
979 /* if gzip encoding is not supported, not sending an Accept-Encoding header at all
980 fixes some issues with buggy versions of PHP */
982 putsock(sock, "Accept-Encoding: %s\r\n", header->accept_encoding);
983 #endif /* HAVE_ZLIB */
984 /* we need to pass our own Host: header, since the one the browser sent would be wrong
985 if we're doing a redirect
986 note: some servers have problems interpreting the port field, omit it if it's 80 */
987 if (header->port == 80)
988 putsock(sock, "Host: %s\r\n", header->host);
990 putsock(sock, "Host: %s:%d\r\n", header->host, header->port);
992 putsock(sock, "Connection: keep-alive\r\n");
995 if (header->location != NULL)
996 putsock(sock, "Location: %s\r\n", header->location);
998 if (header->proxy_authenticate != NULL)
999 putsock(sock, "Proxy-Authenticate: %s\r\n", header->proxy_authenticate);
1001 if (header->content_encoding != NULL)
1002 putsock(sock, "Content-Encoding: %s\r\n", header->content_encoding);
1004 putsock(sock, "Connection: %s\r\n", (connection->keepalive_client) ? "keep-alive" : "close");
1005 putsock(sock, "Proxy-Connection: %s\r\n", (connection->keepalive_client) ? "keep-alive" : "close");
1009 putsock(sock, "\r\n");
1015 return TRUE if header type isn't allowed to be passed, otherwise return FALSE
1017 int bad_header(char *type, int flags)
1021 if (!strcasecmp(type, "Connection") || !strncasecmp(type, "Proxy-", 6) || !strcasecmp(type, "Location") || !strncasecmp(type, "Content-", 8) || !strcasecmp(type, "Transfer-Encoding"))
1025 case HEADER_FORWARD:
1026 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"))
1034 return an emtpy HEADER * struct
1036 HEADER *header_new()
1040 header = xmalloc(sizeof(HEADER));
1042 header->proto = NULL;
1043 header->host = NULL;
1044 header->file = NULL;
1045 header->method = NULL;
1046 header->version = 0;
1050 header->header = NULL;
1051 header->header_filtered = NULL;
1052 header->content_length = -1;
1053 header->referer = NULL;
1054 header->chunked = FALSE;
1055 /* these need to be initialized as -1, since what we do when the client or server doesn't send a Connection:
1056 header is determined by the protocol version */
1057 header->keepalive = -1;
1058 header->proxy_keepalive = -1;
1059 header->content_type = NULL;
1060 header->content_encoding = NULL;
1061 header->accept_encoding = NULL;
1062 header->location = NULL;
1063 header->url_command = NULL;
1064 header->host_header = NULL;
1065 header->proxy_authenticate = NULL;
1066 header->proxy_authorization = NULL;
1070 HEADER *http_header_dup(HEADER * h)
1074 header = xmalloc(sizeof(HEADER));
1076 header->proto = (h->proto != NULL) ? xstrdup(h->proto) : NULL;
1077 header->host = (h->host != NULL) ? xstrdup(h->host) : NULL;
1078 header->file = (h->file != NULL) ? xstrdup(h->file) : NULL;
1079 header->method = (h->method != NULL) ? xstrdup(h->method) : NULL;
1080 header->version = h->version;
1081 header->code = h->code;
1082 header->type = h->type;
1083 header->port = h->port;
1084 header->header = http_header_list_dup(h->header);
1085 header->header_filtered = http_header_list_dup(h->header_filtered);
1086 header->content_length = h->content_length;
1087 header->chunked = h->chunked;
1088 header->keepalive = h->keepalive;
1089 header->proxy_keepalive = h->proxy_keepalive;
1090 header->content_type = (h->content_type != NULL) ? xstrdup(h->content_type) : NULL;
1091 header->content_encoding = (h->content_encoding != NULL) ? xstrdup(h->content_encoding) : NULL;
1092 header->accept_encoding = (h->accept_encoding != NULL) ? xstrdup(h->accept_encoding) : NULL;
1093 header->location = (h->location != NULL) ? xstrdup(h->location) : NULL;
1094 header->url_command = NULL;
1095 header->host_header = (h->host_header != NULL) ? xstrdup(h->host_header) : NULL;
1096 header->proxy_authenticate = (h->proxy_authenticate != NULL) ? xstrdup(h->proxy_authenticate) : NULL;
1097 header->proxy_authorization = (h->proxy_authorization != NULL) ? xstrdup(h->proxy_authorization) : NULL;
1098 header->referer = (h->referer != NULL) ? xstrdup(h->referer) : NULL;
1104 parse options prefixed to a url, these can be stacked.. i.e. debug..bypass[r]..host.com
1106 struct url_command_t **url_command_parse(char *url)
1109 char *end, *ptr, *ptr2;
1110 struct url_command_t **ret = NULL;
1112 while ((end = strstr(url, ".."))) {
1113 ret = xrealloc(ret, (count + 2) * sizeof(struct url_command_t *));
1114 ret[count] = xmalloc(sizeof(struct url_command_t));
1116 ret[count + 1] = NULL;
1118 ptr = memchr(url, '[', end - url);
1122 ptr2 = memchr(ptr, ']', end - url);
1124 ret[count]->options = xstrndup(&ptr[1], ptr2 - ptr - 1);
1126 ret[count]->options = NULL;
1128 ret[count]->command = xstrndup(url, (ptr != NULL) ? ptr - url : end - url);
1130 strcpy(url, (ptr2 != NULL) ? &ptr2[3] : &end[2]);
1138 char *url_command_create(struct url_command_t **url_command) {
1142 filebuf = filebuf_new();
1144 for (; *url_command; url_command++) {
1145 if ((*url_command)->options != NULL)
1146 filebuf_addf(filebuf, "%s[%s]..", (*url_command)->command, (*url_command)->options);
1148 filebuf_addf(filebuf, "%s..", (*url_command)->command);
1151 filebuf_add(filebuf, "", 1);
1153 filebuf_shorten(filebuf);
1154 ret = filebuf->data;
1155 filebuf->data = NULL;
1157 filebuf_free(filebuf);
1162 void url_command_free(struct url_command_t **url_command)
1164 struct url_command_t **tmp = url_command;
1166 while (*tmp != NULL) {
1167 FREE_AND_NULL((*tmp)->command);
1168 FREE_AND_NULL((*tmp)->options);
1178 /* prefix URL command to a URL */
1179 char *url_command_add(CONNECTION *connection, char *url) {
1180 char *uc, *ptr, buf[8096];
1182 uc = url_command_create(connection->header->url_command);
1185 snprintf(buf, sizeof(buf), "http://%s%s:%d%s", uc, connection->header->host, connection->header->port, url);
1187 ptr = strstr(url, "://");
1188 if ((ptr != NULL && !strncasecmp(url, "http", 4)) || ptr == NULL) {
1194 snprintf(buf, sizeof(buf), "http://%s%s", uc, ptr);
1200 return xstrdup(buf);