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
24 REDIRECT_LIST *redirect_load(REDIRECT_LIST * redirect_list, XML_LIST * xml_list)
26 REDIRECT_LIST *tmp_list = redirect_list;
27 struct REDIRECT_LIST_LIST *redirect = NULL;
29 if (tmp_list == NULL) {
30 tmp_list = xmalloc(sizeof(REDIRECT_LIST));
31 tmp_list->redirect_list = NULL;
33 tmp_list->enabled = TRUE;
35 redirect_list = tmp_list;
37 pthread_rwlock_init(&tmp_list->lock, NULL);
39 redirect = tmp_list->redirect_list;
41 while ((xml_list = xml_section(xml_list, "<redirect>"))) {
42 XML_LIST_LOOP(xml_list, "<redirect>") {
43 XML_LIST_CMP(xml_list, "<item>") {
44 redirect = redirect_list_new(redirect);
45 redirect->id = redirect_list->id++;
47 if (tmp_list->redirect_list == NULL)
48 tmp_list->redirect_list = redirect;
49 XML_LIST_LOOP(xml_list, "<item>") {
50 XML_LIST_CMP(xml_list, "<enabled>") {
51 xml_list = xml_list->next;
52 if (xml_list->type == XML_VALUE) {
53 if (!strcasecmp(xml_list->item, "false"))
54 redirect->enabled = FALSE;
56 redirect->enabled = TRUE;
59 XML_LIST_CMP(xml_list, "<comment>") {
60 xml_list = xml_list->next;
61 if (xml_list->type == XML_VALUE)
62 redirect_list_insert(redirect, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL);
64 XML_LIST_CMP(xml_list, "<url>") {
65 xml_list = xml_list->next;
66 if (xml_list->type == XML_VALUE)
67 redirect_list_insert(redirect, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL);
69 XML_LIST_CMP(xml_list, "<redirect>") {
70 xml_list = xml_list->next;
71 if (xml_list->type == XML_VALUE)
72 redirect_list_insert(redirect, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL);
74 XML_LIST_CMP(xml_list, "<port>") {
75 xml_list = xml_list->next;
76 if (xml_list->type == XML_VALUE)
77 redirect_list_insert(redirect, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL);
79 XML_LIST_CMP(xml_list, "<which>") {
80 xml_list = xml_list->next;
81 if (xml_list->type == XML_VALUE)
82 redirect_list_insert(redirect, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL);
84 XML_LIST_CMP(xml_list, "<send302>") {
85 xml_list = xml_list->next;
86 if (xml_list->type == XML_VALUE)
87 redirect_list_insert(redirect, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL);
89 XML_LIST_CMP(xml_list, "<options>") {
90 xml_list = xml_list->next;
91 if (xml_list->type == XML_VALUE)
92 redirect_list_insert(redirect, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item);
96 XML_LIST_CMP(xml_list, "<enabled>") {
97 xml_list = xml_list->next;
98 if (xml_list->type == XML_VALUE) {
99 if (!strcasecmp(xml_list->item, "false"))
100 tmp_list->enabled = FALSE;
102 tmp_list->enabled = TRUE;
111 XML_LIST *redirect_xml(REDIRECT_LIST * redirect_list, XML_LIST * xml_list)
114 struct REDIRECT_LIST_LIST *rl;
116 pthread_rwlock_rdlock(&redirect_list->lock);
118 xml_list = xml_list_add(xml_list, "<redirect>", XML_TAG);
120 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
121 xml_list = xml_list_add(xml_list, (redirect_list->enabled == TRUE) ? "true" : "false", XML_VALUE);
122 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
124 for (rl = redirect_list->redirect_list; rl; rl = rl->next) {
125 xml_list = xml_list_add(xml_list, "<item>", XML_TAG);
127 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
128 xml_list = xml_list_add(xml_list, (rl->enabled == TRUE) ? "true" : "false", XML_VALUE);
129 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
131 if (rl->comment != NULL) {
132 xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
133 ptr = string_to_xml(rl->comment);
134 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
136 xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
139 if (rl->url != NULL) {
140 xml_list = xml_list_add(xml_list, "<url>", XML_TAG);
141 ptr = string_to_xml(rl->url);
142 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
144 xml_list = xml_list_add(xml_list, "</url>", XML_TAG);
147 if (rl->redirect != NULL) {
148 xml_list = xml_list_add(xml_list, "<redirect>", XML_TAG);
149 ptr = string_to_xml(rl->redirect);
150 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
152 xml_list = xml_list_add(xml_list, "</redirect>", XML_TAG);
155 if (rl->port != -1) {
156 xml_list = xml_list_add(xml_list, "<port>", XML_TAG);
157 snprintf(buf, sizeof(buf), "%d", rl->port);
158 xml_list = xml_list_add(xml_list, buf, XML_VALUE);
159 xml_list = xml_list_add(xml_list, "</port>", XML_TAG);
162 xml_list = xml_list_add(xml_list, "<which>", XML_TAG);
163 xml_list = xml_list_add(xml_list, (rl->which == REDIRECT_BOTH) ? "both" : (rl->which == REDIRECT_URL) ? "url" : "location", XML_VALUE);
164 xml_list = xml_list_add(xml_list, "</which>", XML_TAG);
166 xml_list = xml_list_add(xml_list, "<send302>", XML_TAG);
167 xml_list = xml_list_add(xml_list, (rl->send302 == TRUE) ? "yes" : "no", XML_VALUE);
168 xml_list = xml_list_add(xml_list, "</send302>", XML_TAG);
170 xml_list = xml_list_add(xml_list, "<options>", XML_TAG);
171 snprintf(buf, sizeof(buf), "%s,%s,%s", (rl->options & URL_ENCODE) ? "encode" : "", (rl->options & URL_DECODEBEFORE) ? "decodebefore" : "", (rl->options & URL_DECODEAFTER) ? "decodeafter" : "");
172 xml_list = xml_list_add(xml_list, buf, XML_VALUE);
173 xml_list = xml_list_add(xml_list, "</options>", XML_TAG);
175 xml_list = xml_list_add(xml_list, "</item>", XML_TAG);
178 xml_list = xml_list_add(xml_list, "</redirect>", XML_TAG);
180 pthread_rwlock_unlock(&redirect_list->lock);
185 struct REDIRECT_LIST_LIST *redirect_list_new(struct REDIRECT_LIST_LIST *x)
188 x = xmalloc(sizeof(struct REDIRECT_LIST_LIST));
191 while (x->next != NULL)
193 x->next = xmalloc(sizeof(struct REDIRECT_LIST_LIST));
204 x->which = REDIRECT_BOTH;
212 void redirect_list_insert(struct REDIRECT_LIST_LIST *x, char *a, char *b, char *c, char *d, char *e, char *f, char *g)
218 FREE_AND_NULL(x->comment);
221 x->comment = xstrdup(a);
226 FREE_AND_NULL(x->url);
229 x->up = reg_sub_compile(b, PCREFLAGS);
235 FREE_AND_NULL(x->redirect);
238 x->redirect = xstrdup(c);
247 x->which = REDIRECT_BOTH;
250 if (!strcasecmp(e, "location"))
251 x->which = REDIRECT_HEADER;
252 else if (!strcasecmp(e, "url"))
253 x->which = REDIRECT_URL;
260 if (!strcasecmp(f, "yes"))
270 args = string_break(g, ',');
271 for (i = 0; args[i]; i++) {
272 if (!strcasecmp(args[i], "encode"))
273 x->options |= URL_ENCODE;
274 else if (!strcasecmp(args[i], "decodeafter"))
275 x->options |= URL_DECODEAFTER;
276 else if (!strcasecmp(args[i], "decodebefore"))
277 x->options |= URL_DECODEBEFORE;
286 struct REDIRECT_LIST_LIST *redirect_list_delete(struct REDIRECT_LIST_LIST *x)
288 struct REDIRECT_LIST_LIST *start = x;
290 while (start->prev != NULL)
294 x->next->prev = x->prev;
296 x->prev->next = x->next;
302 FREE_AND_NULL(x->comment);
303 FREE_AND_NULL(x->url);
304 FREE_AND_NULL(x->redirect);
311 void redirect_free(REDIRECT_LIST * redirect_list)
313 if (redirect_list == NULL)
316 redirect_list_free(redirect_list->redirect_list);
318 xfree(redirect_list);
321 void redirect_list_free(struct REDIRECT_LIST_LIST *rl)
323 struct REDIRECT_LIST_LIST *tmp;
329 reg_sub_free(rl->up);
330 FREE_AND_NULL(rl->comment);
331 FREE_AND_NULL(rl->url);
332 FREE_AND_NULL(rl->redirect);
339 int redirect_do(REDIRECT_LIST * redirect_list, CONNECTION * connection, int type)
342 char url[1024], *ret, *ptr, *ptr2;
343 struct REDIRECT_LIST_LIST *rl;
344 regmatch_sub_t *rmatch;
347 if (redirect_list == NULL)
349 if (connection->bypass & FEATURE_REDIRECT)
352 pthread_rwlock_rdlock(&redirect_list->lock);
354 if (redirect_list->enabled == FALSE) {
355 pthread_rwlock_unlock(&redirect_list->lock);
360 if (type == REDIRECT_REQUEST)
361 snprintf(url, sizeof(url), "%s%s", (connection->header->host != NULL) ? connection->header->host : "", connection->header->file);
363 ptr = (!strncasecmp(connection->rheader->location, "http://", 7)) ? connection->rheader->location + 7 : connection->rheader->location;
366 snprintf(url, sizeof(url), "%s%s", connection->rheader->host, connection->rheader->location);
368 snprintf(url, sizeof(url), "%s", ptr);
371 for (rl = redirect_list->redirect_list; rl; rl = rl->next) {
372 if (rl->up != NULL && rl->enabled == TRUE && (rl->which == REDIRECT_BOTH || (rl->which == REDIRECT_URL && type == REDIRECT_REQUEST) || (rl->which == REDIRECT_LOCATION && type == REDIRECT_HEADER))) {
373 if (rl->options & URL_DECODEBEFORE) {
374 /* decode url before matching */
375 ret = url_decode(url, strlen(url));
376 rmatch = reg_sub_exec(rl->up, ret);
379 rmatch = reg_sub_exec(rl->up, url);
381 if (rmatch != NULL) {
382 /* make redirect rules with empty redirect url still match, but do nothing */
383 if (rl->redirect == NULL)
386 ret = reg_sub_parse(rmatch, rl->redirect);
388 ptr = strchr(ret, '/');
389 if (ptr != NULL && (rl->options & URL_ENCODE || rl->options & URL_DECODEAFTER)) {
390 /* encode or decode file portion of url */
391 ptr2 = (rl->options & URL_ENCODE) ? url_encode(&ptr[1], strlen(&ptr[1])) : url_decode(&ptr[1], strlen(&ptr[1]));
392 ret = xrealloc(ret, ptr - ret + strlen(ptr2) + 2);
394 ptr = strchr(ret, '/');
396 strcpy(&ptr[1], ptr2);
401 if (type == REDIRECT_REQUEST) {
402 if (rl->send302 == TRUE) {
403 putlog(MMLOG_REDIRECT, "sent 302 redirect for request for %s to %s", url, ret);
405 /* send a 302 redirect */
406 header = header_new();
407 header->type = HTTP_RESP;
409 header->content_length = 0;
412 if (connection->header->url_command != NULL) {
413 ptr = url_command_create(connection->header->url_command);
414 snprintf(url, sizeof(url), "http://%s%s", ptr, ret);
417 snprintf(url, sizeof(url), "http://%s", ret);
419 snprintf(url, sizeof(url), "%s", ret);
421 header->location = xstrdup(url);
423 header_send(header, connection, CLIENT, HEADER_RESP);
425 http_header_free(header);
428 /* just connect to a different host */
429 if (ptr == NULL || *ret != '/') {
430 FREE_AND_NULL(connection->header->host);
431 connection->header->host = xstrndup(ret, (ptr != NULL) ? ptr - ret : ~0);
434 FREE_AND_NULL(connection->header->file);
435 connection->header->file = xstrdup((ptr != NULL) ? ptr : "/");
438 connection->header->port = rl->port;
440 putlog(MMLOG_REDIRECT, "request for %s to %s%s", url, (connection->header->host != NULL) ? connection->header->host : "", connection->header->file);
443 /* change the Location: header from a 302 redirect */
444 snprintf(url, sizeof(url), "%s%s", (*ret == '/') ? "" : "http://", ret);
446 putlog(MMLOG_REDIRECT, "302 redirect for %s to %s", connection->rheader->location, url);
448 xfree(connection->rheader->location);
450 connection->rheader->location = xstrdup(url);
454 reg_sub_match_free(rmatch);
461 pthread_rwlock_unlock(&redirect_list->lock);