3.1 port of Internal Redirector feature Originally by Gonzalo Arana
Internal redirect support in squid3 would make live much easier for us, squid
redirection users.
squid.conf new directives:
url_map_access allow|deny acl-name [acl-name [acl-name ...] ]
url_map_access allow|deny acl-name [acl-name [acl-name ...] ]
ul_map new-url acl-name [acl-name [acl-name ...] ]
where 'new-url' format codes will be:
%[#]formatcode
'#' means URL quoted (%hex representation of non-alphanumeric characters).
%>a Client source IP address
%la Local IP address (http_port)
%lp Local port number (http_port)
%ts Seconds since epoch
%tu subsecond time (milliseconds, %03d)
%un User name
%ul User login
%ui User ident
%ue User from external acl
%rm Request method (GET/POST etc)
%ru Request URL
%rp Request path
%rh Request host from URL
%rH Request Host header
%rP Request protocol
%et Tag returned by external acl
%ea Log string returned by external acl
%% a literal % character
This port alters:
- Directive names to 'url_map' and 'url_map_access' which better describe
their actions (mapping URL to another form in transit).
- Adds the --enable-url-maps configure option
- Moves global API objects into a feature-specific header
It also polishes the makefiles slightly by grouping all redirection files
together nicely to reduce code duplication.
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [EMAIL PROTECTED]
# target_branch: file:///src/squid/bzr/trunk/
# testament_sha1: 96d4661f6e03163bd3aabb4dee5de8856bf9136e
# timestamp: 2008-05-24 00:02:16 +1200
# message: bug1208
# base_revision_id: [EMAIL PROTECTED]
# nw8puapy7si4qmd2
#
# Begin patch
=== modified file 'configure.in'
--- configure.in 2008-05-17 11:27:47 +0000
+++ configure.in 2008-05-23 11:50:25 +0000
@@ -1914,6 +1914,20 @@
fi
])
+dnl Enable internal URL-rewriting
+AC_MSG_CHECKING([whether internal URL re-writing is wanted])
+AC_ARG_ENABLE(url-maps,
+[ --enable-url-maps Enable internal URL re-writing],
+[ if test "$enableval" = "yes" ; then
+ echo "Enabling internal URL re-writing"
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(USE_URLMAPS,1,[Internal URL re-writing])
+ else
+ AC_MSG_RESULT(no)
+ AC_DEFINE(USE_URLMAPS,0,[Internal URL re-writing])
+ fi
+])
+
dnl Optional CNAME-Recursion by Internal DNS engine
AC_MSG_CHECKING([whether DNS CNAME recursion wanted])
AC_ARG_WITH(dns-cname,
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2008-05-01 15:35:17 +0000
+++ src/Makefile.am 2008-05-23 11:47:08 +0000
@@ -288,6 +288,11 @@
DiskIO/DiskIOModule.h \
DiskIO/ReadRequest.h
+REDIRECT_SOURCE= \
+ InternalRedirect.h \
+ InternalRedirect.cc \
+ redirect.cc
+
all_AUTHMODULES = \
auth/basic/basicScheme.cc \
auth/basic/basicScheme.h \
@@ -596,7 +601,7 @@
PeerSelectState.h \
PingData.h \
protos.h \
- redirect.cc \
+ $(REDIRECT_SOURCE) \
referer.cc \
refresh.cc \
RemovalPolicy.cc \
@@ -891,7 +896,7 @@
peer_digest.cc \
peer_select.cc \
protos.h \
- redirect.cc \
+ $(REDIRECT_SOURCE) \
referer.cc \
refresh.cc \
RemovalPolicy.cc \
@@ -1435,7 +1440,7 @@
pconn.cc \
peer_digest.cc \
peer_select.cc \
- redirect.cc \
+ $(REDIRECT_SOURCE) \
referer.cc \
refresh.cc \
RemovalPolicy.cc \
@@ -1606,7 +1611,7 @@
pconn.cc \
peer_digest.cc \
peer_select.cc \
- redirect.cc \
+ $(REDIRECT_SOURCE) \
referer.cc \
refresh.cc \
Server.cc \
@@ -1762,7 +1767,7 @@
pconn.cc \
peer_digest.cc \
peer_select.cc \
- redirect.cc \
+ $(REDIRECT_SOURCE) \
referer.cc \
refresh.cc \
Server.cc \
@@ -1908,7 +1913,7 @@
peer_digest.cc \
peer_select.cc \
pconn.cc \
- redirect.cc \
+ $(REDIRECT_SOURCE) \
referer.cc \
refresh.cc \
RemovalPolicy.cc \
@@ -2068,7 +2073,7 @@
pconn.cc \
peer_digest.cc \
peer_select.cc \
- redirect.cc \
+ $(REDIRECT_SOURCE) \
referer.cc \
refresh.cc \
RemovalPolicy.cc \
@@ -2430,7 +2435,7 @@
pconn.cc \
peer_digest.cc \
peer_select.cc \
- redirect.cc \
+ $(REDIRECT_SOURCE) \
referer.cc \
refresh.cc \
Server.cc \
=== modified file 'src/auth/negotiate/auth_negotiate.h'
--- src/auth/negotiate/auth_negotiate.h 2008-04-21 12:05:23 +0000
+++ src/auth/negotiate/auth_negotiate.h 2008-05-23 11:47:08 +0000
@@ -40,7 +40,8 @@
AuthUserRequest *auth_user_request;
RH *handler;
} authenticateStateData;
-#endif
+
+#endif /* __AUTH_AUTHENTICATE_STATE_T__ */
/// \ingroup AuthNegotiateAPI
class NegotiateUser : public AuthUser
@@ -135,4 +136,4 @@
/// \ingroup AuthNegotiateAPI
typedef class AuthNegotiateConfig auth_negotiate_config;
-#endif
+#endif /* __AUTH_NEGOTIATE_H__ */
=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc 2008-05-22 03:05:40 +0000
+++ src/cache_cf.cc 2008-05-23 11:50:25 +0000
@@ -459,6 +459,7 @@
#endif
+ //TODO: garana: if redirect_program && redirects => warning
if (Config.Program.redirect) {
if (Config.redirectChildren < 1) {
Config.redirectChildren = 0;
=== modified file 'src/cf.data.depend'
--- src/cf.data.depend 2008-04-03 05:31:29 +0000
+++ src/cf.data.depend 2008-05-23 11:47:08 +0000
@@ -21,7 +21,7 @@
externalAclHelper auth_param
hostdomain cache_peer
hostdomaintype cache_peer
-http_header_access
+http_header_access acl
http_header_replace
http_port_list
https_port_list
@@ -46,6 +46,7 @@
time_t
tristate
uri_whitespace
+url_map acl
ushort
wccp2_service
wccp2_service_info
=== modified file 'src/cf.data.pre'
--- src/cf.data.pre 2008-05-22 03:05:40 +0000
+++ src/cf.data.pre 2008-05-23 11:50:25 +0000
@@ -2595,6 +2595,69 @@
-----------------------------------------------------------------------------
COMMENT_END
+NAME: url_map
+TYPE: url_map
+IFDEF: USE_URLMAPS
+LOC: Config.url_maps
+DEFAULT: none
+DOC_START
+ Secifiy an internal redirection rule. The format is:
+
+ url_map dsturl acl [acl [acl ..]]
+
+ The URL is mapped when all acls are matched.
+
+ If dsturl is "-" the re-write does nothing.
+
+ dsturl may start with a status code sent directly to user. Valid
+ status codes:
+
+ 301:http://.... Means respond with a 301 to user.
+ 302:http://.... Means respond with a 302 to user.
+ 303:http://.... Means respond with a 303 to user.
+ 307:http://.... Means respond with a 307 to user.
+
+ dsturl may have format codes preceeded by %.
+ Format:
+
+ %[#][argument]formatcode
+
+ # URL quoted output format
+
+ Valid format codes:
+
+ >a Client source IP address
+ la Local IP address (http_port)
+ lp Local port number (http_port)
+ ts Seconds since epoch
+ tu subsecond time (milliseconds, %03d)
+ un User name
+ ul User login
+ ui User ident
+ ue User from external acl
+ rm Request method (GET/POST etc)
+ ru Request URL
+ rp Request path
+ rh Request host from URL
+ rH Request Host header
+ rP Request protocol
+ et Tag returned by external acl
+ ea Log string returned by external acl
+ % a literal % character
+
+DOC_END
+
+NAME: url_map_access
+TYPE: acl_access
+IFDEF: USE_URLMAPS
+DEFAULT: none
+LOC: Config.accessList.redirect_internal
+DOC_START
+ If defined, this access list specifies which requests are
+ processed by redirect directives. By default all requests
+ are processed.
+DOC_END
+
NAME: url_rewrite_program redirect_program
TYPE: wordlist
LOC: Config.Program.redirect
=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc 2008-04-04 17:11:00 +0000
+++ src/client_side_request.cc 2008-05-23 11:47:08 +0000
@@ -93,7 +93,6 @@
/* other */
static void clientAccessCheckDoneWrapper(int, void *);
static int clientHierarchical(ClientHttpRequest * http);
-static void clientInterpretRequestHeaders(ClientHttpRequest * http);
static RH clientRedirectDoneWrapper;
static PF checkNoCacheDoneWrapper;
extern "C" CSR clientGetMoreData;
@@ -536,8 +535,15 @@
if (Config.accessList.redirector) {
acl_checklist = clientAclChecklistCreate(Config.accessList.redirector, http);
acl_checklist->nonBlockingCheck(clientRedirectAccessCheckDone, this);
- } else
+ } else {
+#if USE_URLMAPS
+ /* try the internal URL-mappings instead of re-writer program. */
+ clientInternalRedirectStart(this);
+#else
+ // AYJ: whats this? a callback when we don't need one?
redirectStart(http, clientRedirectDoneWrapper, this);
+#endif
+ }
}
static int
@@ -590,7 +596,7 @@
}
-static void
+void
clientInterpretRequestHeaders(ClientHttpRequest * http)
{
HttpRequest *request = http->request;
=== modified file 'src/client_side_request.h'
--- src/client_side_request.h 2008-04-13 13:04:31 +0000
+++ src/client_side_request.h 2008-05-23 11:47:08 +0000
@@ -190,10 +190,10 @@
SQUIDCEXTERN ACLChecklist *clientAclChecklistCreate(const acl_access * acl,ClientHttpRequest * http);
SQUIDCEXTERN int clientHttpRequestStatus(int fd, ClientHttpRequest const *http);
SQUIDCEXTERN void clientAccessCheck(ClientHttpRequest *);
+SQUIDCEXTERN void clientInterpretRequestHeaders(ClientHttpRequest * http);
/* ones that should be elsewhere */
SQUIDCEXTERN void redirectStart(ClientHttpRequest *, RH *, void *);
-
SQUIDCEXTERN void tunnelStart(ClientHttpRequest *, int64_t *, int *);
#ifdef _USE_INLINE_
=== modified file 'src/structs.h'
--- src/structs.h 2008-05-02 10:59:20 +0000
+++ src/structs.h 2008-05-23 11:47:08 +0000
@@ -139,6 +139,11 @@
class external_acl;
class Store;
+/* for struct redirect */
+#if USE_URLMAPS
+#include "InternalRedirect.h"
+#endif
+
struct SquidConfig
{
@@ -493,6 +498,9 @@
#endif
acl_access *redirector;
+#if USE_URLMAPS
+ acl_access *redirect_internal;
+#endif
acl_access *reply;
acl_address *outgoing_address;
acl_tos *outgoing_tos;
@@ -643,6 +651,9 @@
#if USE_LOADABLE_MODULES
wordlist *loadable_module_names;
#endif
+#if USE_URLMAPS
+ redirect* url_maps;
+#endif
};
SQUIDCEXTERN SquidConfig Config;
# Begin bundle
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
ckU4UJAnv7Fn