]> git.ipfire.org Git - thirdparty/squid.git/blob - src/redirect.cc
sourceformat: split protos.h into more specific headers, change many functions' likag...
[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 "SquidConfig.h"
48 #include "Store.h"
49 #if USE_AUTH
50 #include "auth/UserRequest.h"
51 #endif
52 #if USE_SSL
53 #include "ssl/support.h"
54 #endif
55
56 /// url maximum lengh + extra informations passed to redirector
57 #define MAX_REDIRECTOR_REQUEST_STRLEN (MAX_URL + 1024)
58
59 typedef struct {
60 void *data;
61 char *orig_url;
62
63 Ip::Address client_addr;
64 const char *client_ident;
65 const char *method_s;
66 RH *handler;
67 } redirectStateData;
68
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);
75
76 static void
77 redirectHandleReply(void *data, char *reply)
78 {
79 redirectStateData *r = static_cast<redirectStateData *>(data);
80 char *t;
81 void *cbdata;
82 debugs(61, 5, "redirectHandleRead: {" << (reply && *reply != '\0' ? reply : "<NULL>") << "}");
83
84 if (reply) {
85 if ((t = strchr(reply, ' ')))
86 *t = '\0';
87
88 if (*reply == '\0')
89 reply = NULL;
90 }
91
92 if (cbdataReferenceValidDone(r->data, &cbdata))
93 r->handler(cbdata, reply);
94
95 redirectStateFree(r);
96 }
97
98 static void
99 redirectStateFree(redirectStateData * r)
100 {
101 safe_free(r->orig_url);
102 cbdataFree(r);
103 }
104
105 static void
106 redirectStats(StoreEntry * sentry)
107 {
108 if (redirectors == NULL) {
109 storeAppendPrintf(sentry, "No redirectors defined\n");
110 return;
111 }
112
113 helperStats(sentry, redirectors, "Redirector Statistics");
114
115 if (Config.onoff.redirector_bypass)
116 storeAppendPrintf(sentry, "\nNumber of requests bypassed "
117 "because all redirectors were busy: %d\n", n_bypassed);
118 }
119
120 /**** PUBLIC FUNCTIONS ****/
121
122 void
123 redirectStart(ClientHttpRequest * http, RH * handler, void *data)
124 {
125 ConnStateData * conn = http->getConn();
126 redirectStateData *r = NULL;
127 const char *fqdn;
128 char buf[MAX_REDIRECTOR_REQUEST_STRLEN];
129 int sz;
130 http_status status;
131 char claddr[MAX_IPSTRLEN];
132 char myaddr[MAX_IPSTRLEN];
133 assert(http);
134 assert(handler);
135 debugs(61, 5, "redirectStart: '" << http->uri << "'");
136
137 if (Config.onoff.redirector_bypass && redirectors->stats.queue_size) {
138 /* Skip redirector if there is one request queued */
139 ++n_bypassed;
140 handler(data, NULL);
141 return;
142 }
143
144 r = cbdataAlloc(redirectStateData);
145 r->orig_url = xstrdup(http->uri);
146 if (conn != NULL)
147 r->client_addr = conn->log_addr;
148 else
149 r->client_addr.SetNoAddr();
150 r->client_ident = NULL;
151 #if USE_AUTH
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"));
155 }
156 #endif
157
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"));
162 }
163
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"));
167 }
168
169 #if USE_SSL
170
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"));
174 }
175 #endif
176
177 if (!r->client_ident)
178 r->client_ident = dash_str;
179
180 r->method_s = RequestMethodStr(http->request->method);
181
182 r->handler = handler;
183
184 r->data = cbdataReference(data);
185
186 if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
187 fqdn = dash_str;
188
189 sz = snprintf(buf, MAX_REDIRECTOR_REQUEST_STRLEN, "%s %s/%s %s %s myip=%s myport=%d\n",
190 r->orig_url,
191 r->client_addr.NtoA(claddr,MAX_IPSTRLEN),
192 fqdn,
193 r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
194 r->method_s,
195 http->request->my_addr.NtoA(myaddr,MAX_IPSTRLEN),
196 http->request->my_addr.GetPort());
197
198 if ((sz<=0) || (sz>=MAX_REDIRECTOR_REQUEST_STRLEN)) {
199 if (sz<=0) {
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.");
202 } else {
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.");
205 }
206
207 clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data;
208 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
209 assert (repContext);
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,
216 http->request,
217 NULL,
218 #if USE_AUTH
219 http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
220 http->getConn()->auth_user_request : http->request->auth_user_request);
221 #else
222 NULL);
223 #endif
224
225 node = (clientStreamNode *)http->client_stream.tail->data;
226 clientStreamRead(node, http, node->readBuffer);
227 return;
228 }
229
230 debugs(61,6, HERE << "sending '" << buf << "' to the helper");
231 helperSubmit(redirectors, buf, redirectHandleReply, r);
232 }
233
234 static void
235 redirectRegisterWithCacheManager(void)
236 {
237 Mgr::RegisterAction("redirector", "URL Redirector Stats", redirectStats, 0, 1);
238 }
239
240 void
241 redirectInit(void)
242 {
243 static int init = 0;
244
245 redirectRegisterWithCacheManager();
246
247 if (!Config.Program.redirect)
248 return;
249
250 if (redirectors == NULL)
251 redirectors = new helper("redirector");
252
253 redirectors->cmdline = Config.Program.redirect;
254
255 redirectors->childs.updateLimits(Config.redirectChildren);
256
257 redirectors->ipc_type = IPC_STREAM;
258
259 helperOpenServers(redirectors);
260
261 if (!init) {
262 init = 1;
263 CBDATA_INIT_TYPE(redirectStateData);
264 }
265 }
266
267 void
268 redirectShutdown(void)
269 {
270 if (!redirectors)
271 return;
272
273 helperShutdown(redirectors);
274
275 if (!shutting_down)
276 return;
277
278 delete redirectors;
279 redirectors = NULL;
280 }