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