tinyproxy/src/reverse-proxy.c

193 lines
6.5 KiB
C

/* tinyproxy - A fast light-weight HTTP proxy
* Copyright (C) 1999-2005 Robert James Kaes <rjkaes@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Allow tinyproxy to be used as a reverse proxy. */
#include "main.h"
#include "reverse-proxy.h"
#include "conns.h"
#include "heap.h"
#include "html-error.h"
#include "log.h"
#include "conf.h"
/*
* Add entry to the reversepath list
*/
void reversepath_add (const char *path, const char *url,
struct reversepath **reversepath_list)
{
struct reversepath *reverse;
size_t l;
if (url == NULL) {
log_message (LOG_WARNING,
"Illegal reverse proxy rule: missing url");
return;
}
if (!strstr (url, "://")) {
log_message (LOG_WARNING,
"Skipping reverse proxy rule: '%s' is not a valid url",
url);
return;
}
if (path && *path != '/') {
log_message (LOG_WARNING,
"Skipping reverse proxy rule: path '%s' "
"doesn't start with a /", path);
return;
}
reverse = (struct reversepath *) safemalloc (sizeof
(struct reversepath));
if (!reverse) {
log_message (LOG_ERR,
"Unable to allocate memory in reversepath_add()");
return;
}
if (!path)
reverse->path = safestrdup ("/");
else {
l = strlen (path);
if (l && path[l-1] == '/')
reverse->path = safestrdup (path);
else {
reverse->path = safemalloc (l + 2);
memcpy (reverse->path, path, l);
reverse->path[l] = '/';
reverse->path[l+1] = 0;
}
}
reverse->url = safestrdup (url);
reverse->next = *reversepath_list;
*reversepath_list = reverse;
log_message (LOG_INFO,
"Added reverse proxy rule: %s -> %s", reverse->path,
reverse->url);
}
/*
* Check if a request url is in the reversepath list
*/
struct reversepath *reversepath_get (char *url, struct reversepath *reverse)
{
size_t l, lu, lp;
while (reverse) {
lu = strlen (url);
lp = strlen (reverse->path);
if ((
(l = lu) == lp-1 ||
(l = lp) <= lu
) &&
!memcmp(url, reverse->path, l))
return reverse;
reverse = reverse->next;
}
return NULL;
}
/**
* Free a reversepath list
*/
void free_reversepath_list (struct reversepath *reverse)
{
while (reverse) {
struct reversepath *tmp = reverse;
reverse = reverse->next;
safefree (tmp->url);
safefree (tmp->path);
safefree (tmp);
}
}
/*
* Rewrite the URL for reverse proxying.
*/
char *reverse_rewrite_url (struct conn_s *connptr, orderedmap hashofheaders,
char *url, int *status)
{
char *rewrite_url = NULL;
char *cookie = NULL;
char *cookieval;
struct reversepath *reverse = NULL;
*status = 0;
/* Reverse requests always start with a slash */
if (*url == '/') {
/* First try locating the reverse mapping by request url */
reverse = reversepath_get (url, config->reversepath_list);
if (reverse) {
size_t lu = strlen (url);
size_t lrp = strlen (reverse->path);
if (lrp > lu) {
rewrite_url = safestrdup (reverse->path);
*status = 301;
} else {
rewrite_url = safemalloc (
strlen (reverse->url) + lu + 1);
sprintf (rewrite_url, "%s%s", reverse->url, url + lrp);
}
} else if (config->reversemagic
&& (cookie = orderedmap_find (hashofheaders,
"cookie"))) {
/* No match - try the magical tracking cookie next */
if ((cookieval = strstr (cookie, REVERSE_COOKIE "="))
&& (reverse =
reversepath_get (cookieval +
strlen (REVERSE_COOKIE) + 1,
config->reversepath_list)))
{
rewrite_url = (char *) safemalloc
(strlen (url) +
strlen (reverse->url) +
1);
strcpy (rewrite_url, reverse->url);
strcat (rewrite_url, url + 1);
log_message (LOG_INFO,
"Magical tracking cookie says: %s",
reverse->path);
}
}
}
if (rewrite_url == NULL) {
return NULL;
}
log_message (LOG_CONN, "Rewriting URL: %s -> %s", url, rewrite_url);
/* Store reverse path so that the magical tracking cookie can be set */
if (config->reversemagic && reverse)
connptr->reversepath = safestrdup (reverse->path);
return rewrite_url;
}