]> git.ipfire.org Git - thirdparty/squid.git/blob - src/redirect.cc
Debug enhancements for rewrite helper user
[thirdparty/squid.git] / src / redirect.cc
1
2 /*
3 * $Id$
4 *
5 * DEBUG: section 61 Redirector
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37 #if USE_AUTH
38 #include "auth/UserRequest.h"
39 #endif
40 #include "comm/Connection.h"
41 #include "mgr/Registration.h"
42 #include "Store.h"
43 #include "fde.h"
44 #include "client_side_request.h"
45 #include "acl/Checklist.h"
46 #include "HttpRequest.h"
47 #include "client_side.h"
48 #include "client_side_reply.h"
49 #include "helper.h"
50 #include "rfc1738.h"
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 if (!r->client_ident && http->request->extacl_user.defined()) {
158 r->client_ident = http->request->extacl_user.termedBuf();
159 debugs(61, 5, HERE << "acl-user=" << (r->client_ident?r->client_ident:"NULL"));
160 }
161
162 if (!r->client_ident && conn != NULL && conn->clientConnection != NULL && conn->clientConnection->rfc931[0]) {
163 r->client_ident = conn->clientConnection->rfc931;
164 debugs(61, 5, HERE << "ident-user=" << (r->client_ident?r->client_ident:"NULL"));
165 }
166
167 #if USE_SSL
168
169 if (!r->client_ident && conn != NULL && Comm::IsConnOpen(conn->clientConnection)) {
170 r->client_ident = sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl);
171 debugs(61, 5, HERE << "ssl-user=" << (r->client_ident?r->client_ident:"NULL"));
172 }
173 #endif
174
175 if (!r->client_ident)
176 r->client_ident = dash_str;
177
178 r->method_s = RequestMethodStr(http->request->method);
179
180 r->handler = handler;
181
182 r->data = cbdataReference(data);
183
184 if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
185 fqdn = dash_str;
186
187 sz = snprintf(buf, MAX_REDIRECTOR_REQUEST_STRLEN, "%s %s/%s %s %s myip=%s myport=%d\n",
188 r->orig_url,
189 r->client_addr.NtoA(claddr,MAX_IPSTRLEN),
190 fqdn,
191 r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
192 r->method_s,
193 http->request->my_addr.NtoA(myaddr,MAX_IPSTRLEN),
194 http->request->my_addr.GetPort());
195
196 if ((sz<=0) || (sz>=MAX_REDIRECTOR_REQUEST_STRLEN)) {
197 if (sz<=0) {
198 status = HTTP_INTERNAL_SERVER_ERROR;
199 debugs(61, DBG_CRITICAL, "ERROR: Gateway Failure. Can not build request to be passed to redirector. Request ABORTED.");
200 } else {
201 status = HTTP_REQUEST_URI_TOO_LARGE;
202 debugs(61, DBG_CRITICAL, "ERROR: Gateway Failure. Request passed to redirector exceeds MAX_REDIRECTOR_REQUEST_STRLEN (" << MAX_REDIRECTOR_REQUEST_STRLEN << "). Request ABORTED.");
203 }
204
205 clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data;
206 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
207 assert (repContext);
208 Ip::Address tmpnoaddr;
209 tmpnoaddr.SetNoAddr();
210 repContext->setReplyToError(ERR_GATEWAY_FAILURE, status,
211 http->request->method, NULL,
212 http->getConn() != NULL && http->getConn()->clientConnection != NULL ?
213 http->getConn()->clientConnection->remote : tmpnoaddr,
214 http->request,
215 NULL,
216 #if USE_AUTH
217 http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
218 http->getConn()->auth_user_request : http->request->auth_user_request);
219 #else
220 NULL);
221 #endif
222
223 node = (clientStreamNode *)http->client_stream.tail->data;
224 clientStreamRead(node, http, node->readBuffer);
225 return;
226 }
227
228 debugs(61,6, HERE << "sending '" << buf << "' to the helper");
229 helperSubmit(redirectors, buf, redirectHandleReply, r);
230 }
231
232 static void
233 redirectRegisterWithCacheManager(void)
234 {
235 Mgr::RegisterAction("redirector", "URL Redirector Stats", redirectStats, 0, 1);
236 }
237
238 void
239 redirectInit(void)
240 {
241 static int init = 0;
242
243 redirectRegisterWithCacheManager();
244
245 if (!Config.Program.redirect)
246 return;
247
248 if (redirectors == NULL)
249 redirectors = new helper("redirector");
250
251 redirectors->cmdline = Config.Program.redirect;
252
253 redirectors->childs = Config.redirectChildren;
254
255 redirectors->ipc_type = IPC_STREAM;
256
257 helperOpenServers(redirectors);
258
259 if (!init) {
260 init = 1;
261 CBDATA_INIT_TYPE(redirectStateData);
262 }
263 }
264
265 void
266 redirectShutdown(void)
267 {
268 if (!redirectors)
269 return;
270
271 helperShutdown(redirectors);
272
273 if (!shutting_down)
274 return;
275
276 delete redirectors;
277 redirectors = NULL;
278 }