]> git.ipfire.org Git - thirdparty/squid.git/blob - src/redirect.cc
Merged from trunk
[thirdparty/squid.git] / src / redirect.cc
1 /*
2 * DEBUG: section 61 Redirector
3 * AUTHOR: Duane Wessels
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
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.
16 *
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.
21 *
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.
26 *
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.
30 *
31 */
32
33 #include "squid.h"
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"
39 #include "fde.h"
40 #include "fqdncache.h"
41 #include "globals.h"
42 #include "HttpRequest.h"
43 #include "helper.h"
44 #include "mgr/Registration.h"
45 #include "redirect.h"
46 #include "rfc1738.h"
47 #include "Store.h"
48 #if USE_AUTH
49 #include "auth/UserRequest.h"
50 #endif
51 #if USE_SSL
52 #include "ssl/support.h"
53 #endif
54
55 /// url maximum lengh + extra informations passed to redirector
56 #define MAX_REDIRECTOR_REQUEST_STRLEN (MAX_URL + 1024)
57
58 typedef struct {
59 void *data;
60 char *orig_url;
61
62 Ip::Address client_addr;
63 const char *client_ident;
64 const char *method_s;
65 RH *handler;
66 } redirectStateData;
67
68 static HLPCB redirectHandleReply;
69 static void redirectStateFree(redirectStateData * r);
70 static helper *redirectors = NULL;
71 static OBJH redirectStats;
72 static int n_bypassed = 0;
73 CBDATA_TYPE(redirectStateData);
74
75 static void
76 redirectHandleReply(void *data, char *reply)
77 {
78 redirectStateData *r = static_cast<redirectStateData *>(data);
79 char *t;
80 void *cbdata;
81 debugs(61, 5, "redirectHandleRead: {" << (reply && *reply != '\0' ? reply : "<NULL>") << "}");
82
83 if (reply) {
84 if ((t = strchr(reply, ' ')))
85 *t = '\0';
86
87 if (*reply == '\0')
88 reply = NULL;
89 }
90
91 if (cbdataReferenceValidDone(r->data, &cbdata))
92 r->handler(cbdata, reply);
93
94 redirectStateFree(r);
95 }
96
97 static void
98 redirectStateFree(redirectStateData * r)
99 {
100 safe_free(r->orig_url);
101 cbdataFree(r);
102 }
103
104 static void
105 redirectStats(StoreEntry * sentry)
106 {
107 if (redirectors == NULL) {
108 storeAppendPrintf(sentry, "No redirectors defined\n");
109 return;
110 }
111
112 helperStats(sentry, redirectors, "Redirector Statistics");
113
114 if (Config.onoff.redirector_bypass)
115 storeAppendPrintf(sentry, "\nNumber of requests bypassed "
116 "because all redirectors were busy: %d\n", n_bypassed);
117 }
118
119 /**** PUBLIC FUNCTIONS ****/
120
121 void
122 redirectStart(ClientHttpRequest * http, RH * handler, void *data)
123 {
124 ConnStateData * conn = http->getConn();
125 redirectStateData *r = NULL;
126 const char *fqdn;
127 char buf[MAX_REDIRECTOR_REQUEST_STRLEN];
128 int sz;
129 http_status status;
130 char claddr[MAX_IPSTRLEN];
131 char myaddr[MAX_IPSTRLEN];
132 assert(http);
133 assert(handler);
134 debugs(61, 5, "redirectStart: '" << http->uri << "'");
135
136 if (Config.onoff.redirector_bypass && redirectors->stats.queue_size) {
137 /* Skip redirector if there is one request queued */
138 ++n_bypassed;
139 handler(data, NULL);
140 return;
141 }
142
143 r = cbdataAlloc(redirectStateData);
144 r->orig_url = xstrdup(http->uri);
145 if (conn != NULL)
146 r->client_addr = conn->log_addr;
147 else
148 r->client_addr.SetNoAddr();
149 r->client_ident = NULL;
150 #if USE_AUTH
151 if (http->request->auth_user_request != NULL) {
152 r->client_ident = http->request->auth_user_request->username();
153 debugs(61, 5, HERE << "auth-user=" << (r->client_ident?r->client_ident:"NULL"));
154 }
155 #endif
156
157 // HttpRequest initializes with null_string. So we must check both defined() and size()
158 if (!r->client_ident && http->request->extacl_user.defined() && http->request->extacl_user.size()) {
159 r->client_ident = http->request->extacl_user.termedBuf();
160 debugs(61, 5, HERE << "acl-user=" << (r->client_ident?r->client_ident:"NULL"));
161 }
162
163 if (!r->client_ident && conn != NULL && conn->clientConnection != NULL && conn->clientConnection->rfc931[0]) {
164 r->client_ident = conn->clientConnection->rfc931;
165 debugs(61, 5, HERE << "ident-user=" << (r->client_ident?r->client_ident:"NULL"));
166 }
167
168 #if USE_SSL
169
170 if (!r->client_ident && conn != NULL && Comm::IsConnOpen(conn->clientConnection)) {
171 r->client_ident = sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl);
172 debugs(61, 5, HERE << "ssl-user=" << (r->client_ident?r->client_ident:"NULL"));
173 }
174 #endif
175
176 if (!r->client_ident)
177 r->client_ident = dash_str;
178
179 r->method_s = RequestMethodStr(http->request->method);
180
181 r->handler = handler;
182
183 r->data = cbdataReference(data);
184
185 if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
186 fqdn = dash_str;
187
188 sz = snprintf(buf, MAX_REDIRECTOR_REQUEST_STRLEN, "%s %s/%s %s %s myip=%s myport=%d\n",
189 r->orig_url,
190 r->client_addr.NtoA(claddr,MAX_IPSTRLEN),
191 fqdn,
192 r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
193 r->method_s,
194 http->request->my_addr.NtoA(myaddr,MAX_IPSTRLEN),
195 http->request->my_addr.GetPort());
196
197 if ((sz<=0) || (sz>=MAX_REDIRECTOR_REQUEST_STRLEN)) {
198 if (sz<=0) {
199 status = HTTP_INTERNAL_SERVER_ERROR;
200 debugs(61, DBG_CRITICAL, "ERROR: Gateway Failure. Can not build request to be passed to redirector. Request ABORTED.");
201 } else {
202 status = HTTP_REQUEST_URI_TOO_LARGE;
203 debugs(61, DBG_CRITICAL, "ERROR: Gateway Failure. Request passed to redirector exceeds MAX_REDIRECTOR_REQUEST_STRLEN (" << MAX_REDIRECTOR_REQUEST_STRLEN << "). Request ABORTED.");
204 }
205
206 clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data;
207 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
208 assert (repContext);
209 Ip::Address tmpnoaddr;
210 tmpnoaddr.SetNoAddr();
211 repContext->setReplyToError(ERR_GATEWAY_FAILURE, status,
212 http->request->method, NULL,
213 http->getConn() != NULL && http->getConn()->clientConnection != NULL ?
214 http->getConn()->clientConnection->remote : tmpnoaddr,
215 http->request,
216 NULL,
217 #if USE_AUTH
218 http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
219 http->getConn()->auth_user_request : http->request->auth_user_request);
220 #else
221 NULL);
222 #endif
223
224 node = (clientStreamNode *)http->client_stream.tail->data;
225 clientStreamRead(node, http, node->readBuffer);
226 return;
227 }
228
229 debugs(61,6, HERE << "sending '" << buf << "' to the helper");
230 helperSubmit(redirectors, buf, redirectHandleReply, r);
231 }
232
233 static void
234 redirectRegisterWithCacheManager(void)
235 {
236 Mgr::RegisterAction("redirector", "URL Redirector Stats", redirectStats, 0, 1);
237 }
238
239 void
240 redirectInit(void)
241 {
242 static int init = 0;
243
244 redirectRegisterWithCacheManager();
245
246 if (!Config.Program.redirect)
247 return;
248
249 if (redirectors == NULL)
250 redirectors = new helper("redirector");
251
252 redirectors->cmdline = Config.Program.redirect;
253
254 redirectors->childs.updateLimits(Config.redirectChildren);
255
256 redirectors->ipc_type = IPC_STREAM;
257
258 helperOpenServers(redirectors);
259
260 if (!init) {
261 init = 1;
262 CBDATA_INIT_TYPE(redirectStateData);
263 }
264 }
265
266 void
267 redirectShutdown(void)
268 {
269 if (!redirectors)
270 return;
271
272 helperShutdown(redirectors);
273
274 if (!shutting_down)
275 return;
276
277 delete redirectors;
278 redirectors = NULL;
279 }