2 * DEBUG: section 61 Redirector
3 * AUTHOR: Duane Wessels
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "acl/Checklist.h"
35 #include "client_side.h"
36 #include "client_side_reply.h"
37 #include "client_side_request.h"
38 #include "comm/Connection.h"
40 #include "fqdncache.h"
42 #include "HttpRequest.h"
44 #include "mgr/Registration.h"
47 #include "SquidConfig.h"
50 #include "auth/UserRequest.h"
53 #include "ssl/support.h"
56 /// url maximum lengh + extra informations passed to redirector
57 #define MAX_REDIRECTOR_REQUEST_STRLEN (MAX_URL + 1024)
63 Ip::Address client_addr
;
64 const char *client_ident
;
69 static HLPCB redirectHandleReply
;
70 static void redirectStateFree(redirectStateData
* r
);
71 static helper
*redirectors
= NULL
;
72 static OBJH redirectStats
;
73 static int n_bypassed
= 0;
74 CBDATA_TYPE(redirectStateData
);
77 redirectHandleReply(void *data
, char *reply
)
79 redirectStateData
*r
= static_cast<redirectStateData
*>(data
);
82 debugs(61, 5, "redirectHandleRead: {" << (reply
&& *reply
!= '\0' ? reply
: "<NULL>") << "}");
85 if ((t
= strchr(reply
, ' ')))
92 if (cbdataReferenceValidDone(r
->data
, &cbdata
))
93 r
->handler(cbdata
, reply
);
99 redirectStateFree(redirectStateData
* r
)
101 safe_free(r
->orig_url
);
106 redirectStats(StoreEntry
* sentry
)
108 if (redirectors
== NULL
) {
109 storeAppendPrintf(sentry
, "No redirectors defined\n");
113 helperStats(sentry
, redirectors
, "Redirector Statistics");
115 if (Config
.onoff
.redirector_bypass
)
116 storeAppendPrintf(sentry
, "\nNumber of requests bypassed "
117 "because all redirectors were busy: %d\n", n_bypassed
);
120 /**** PUBLIC FUNCTIONS ****/
123 redirectStart(ClientHttpRequest
* http
, RH
* handler
, void *data
)
125 ConnStateData
* conn
= http
->getConn();
126 redirectStateData
*r
= NULL
;
128 char buf
[MAX_REDIRECTOR_REQUEST_STRLEN
];
131 char claddr
[MAX_IPSTRLEN
];
132 char myaddr
[MAX_IPSTRLEN
];
135 debugs(61, 5, "redirectStart: '" << http
->uri
<< "'");
137 if (Config
.onoff
.redirector_bypass
&& redirectors
->stats
.queue_size
) {
138 /* Skip redirector if there is one request queued */
144 r
= cbdataAlloc(redirectStateData
);
145 r
->orig_url
= xstrdup(http
->uri
);
147 r
->client_addr
= conn
->log_addr
;
149 r
->client_addr
.SetNoAddr();
150 r
->client_ident
= NULL
;
152 if (http
->request
->auth_user_request
!= NULL
) {
153 r
->client_ident
= http
->request
->auth_user_request
->username();
154 debugs(61, 5, HERE
<< "auth-user=" << (r
->client_ident
?r
->client_ident
:"NULL"));
158 // HttpRequest initializes with null_string. So we must check both defined() and size()
159 if (!r
->client_ident
&& http
->request
->extacl_user
.defined() && http
->request
->extacl_user
.size()) {
160 r
->client_ident
= http
->request
->extacl_user
.termedBuf();
161 debugs(61, 5, HERE
<< "acl-user=" << (r
->client_ident
?r
->client_ident
:"NULL"));
164 if (!r
->client_ident
&& conn
!= NULL
&& conn
->clientConnection
!= NULL
&& conn
->clientConnection
->rfc931
[0]) {
165 r
->client_ident
= conn
->clientConnection
->rfc931
;
166 debugs(61, 5, HERE
<< "ident-user=" << (r
->client_ident
?r
->client_ident
:"NULL"));
171 if (!r
->client_ident
&& conn
!= NULL
&& Comm::IsConnOpen(conn
->clientConnection
)) {
172 r
->client_ident
= sslGetUserEmail(fd_table
[conn
->clientConnection
->fd
].ssl
);
173 debugs(61, 5, HERE
<< "ssl-user=" << (r
->client_ident
?r
->client_ident
:"NULL"));
177 if (!r
->client_ident
)
178 r
->client_ident
= dash_str
;
180 r
->method_s
= RequestMethodStr(http
->request
->method
);
182 r
->handler
= handler
;
184 r
->data
= cbdataReference(data
);
186 if ((fqdn
= fqdncache_gethostbyaddr(r
->client_addr
, 0)) == NULL
)
189 sz
= snprintf(buf
, MAX_REDIRECTOR_REQUEST_STRLEN
, "%s %s/%s %s %s myip=%s myport=%d\n",
191 r
->client_addr
.NtoA(claddr
,MAX_IPSTRLEN
),
193 r
->client_ident
[0] ? rfc1738_escape(r
->client_ident
) : dash_str
,
195 http
->request
->my_addr
.NtoA(myaddr
,MAX_IPSTRLEN
),
196 http
->request
->my_addr
.GetPort());
198 if ((sz
<=0) || (sz
>=MAX_REDIRECTOR_REQUEST_STRLEN
)) {
200 status
= HTTP_INTERNAL_SERVER_ERROR
;
201 debugs(61, DBG_CRITICAL
, "ERROR: Gateway Failure. Can not build request to be passed to redirector. Request ABORTED.");
203 status
= HTTP_REQUEST_URI_TOO_LARGE
;
204 debugs(61, DBG_CRITICAL
, "ERROR: Gateway Failure. Request passed to redirector exceeds MAX_REDIRECTOR_REQUEST_STRLEN (" << MAX_REDIRECTOR_REQUEST_STRLEN
<< "). Request ABORTED.");
207 clientStreamNode
*node
= (clientStreamNode
*)http
->client_stream
.tail
->prev
->data
;
208 clientReplyContext
*repContext
= dynamic_cast<clientReplyContext
*>(node
->data
.getRaw());
210 Ip::Address tmpnoaddr
;
211 tmpnoaddr
.SetNoAddr();
212 repContext
->setReplyToError(ERR_GATEWAY_FAILURE
, status
,
213 http
->request
->method
, NULL
,
214 http
->getConn() != NULL
&& http
->getConn()->clientConnection
!= NULL
?
215 http
->getConn()->clientConnection
->remote
: tmpnoaddr
,
219 http
->getConn() != NULL
&& http
->getConn()->auth_user_request
!= NULL
?
220 http
->getConn()->auth_user_request
: http
->request
->auth_user_request
);
225 node
= (clientStreamNode
*)http
->client_stream
.tail
->data
;
226 clientStreamRead(node
, http
, node
->readBuffer
);
230 debugs(61,6, HERE
<< "sending '" << buf
<< "' to the helper");
231 helperSubmit(redirectors
, buf
, redirectHandleReply
, r
);
235 redirectRegisterWithCacheManager(void)
237 Mgr::RegisterAction("redirector", "URL Redirector Stats", redirectStats
, 0, 1);
245 redirectRegisterWithCacheManager();
247 if (!Config
.Program
.redirect
)
250 if (redirectors
== NULL
)
251 redirectors
= new helper("redirector");
253 redirectors
->cmdline
= Config
.Program
.redirect
;
255 redirectors
->childs
.updateLimits(Config
.redirectChildren
);
257 redirectors
->ipc_type
= IPC_STREAM
;
259 helperOpenServers(redirectors
);
263 CBDATA_INIT_TYPE(redirectStateData
);
268 redirectShutdown(void)
273 helperShutdown(redirectors
);