]> git.ipfire.org Git - thirdparty/squid.git/blob - src/redirect.cc
Upgrade comm layer Connection handling
[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 else
154 #endif
155 if (http->request->extacl_user.defined()) {
156 r->client_ident = http->request->extacl_user.termedBuf();
157 }
158
159 if (!r->client_ident && conn != NULL && conn->clientConnection != NULL && conn->clientConnection->rfc931[0])
160 r->client_ident = conn->clientConnection->rfc931;
161
162 #if USE_SSL
163
164 if (!r->client_ident && conn != NULL && Comm::IsConnOpen(conn->clientConnection))
165 r->client_ident = sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl);
166
167 #endif
168
169 if (!r->client_ident)
170 r->client_ident = dash_str;
171
172 r->method_s = RequestMethodStr(http->request->method);
173
174 r->handler = handler;
175
176 r->data = cbdataReference(data);
177
178 if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
179 fqdn = dash_str;
180
181 sz = snprintf(buf, MAX_REDIRECTOR_REQUEST_STRLEN, "%s %s/%s %s %s myip=%s myport=%d\n",
182 r->orig_url,
183 r->client_addr.NtoA(claddr,MAX_IPSTRLEN),
184 fqdn,
185 r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
186 r->method_s,
187 http->request->my_addr.NtoA(myaddr,MAX_IPSTRLEN),
188 http->request->my_addr.GetPort());
189
190 if ((sz<=0) || (sz>=MAX_REDIRECTOR_REQUEST_STRLEN)) {
191 if (sz<=0) {
192 status = HTTP_INTERNAL_SERVER_ERROR;
193 debugs(61, DBG_CRITICAL, "ERROR: Gateway Failure. Can not build request to be passed to redirector. Request ABORTED.");
194 } else {
195 status = HTTP_REQUEST_URI_TOO_LARGE;
196 debugs(61, DBG_CRITICAL, "ERROR: Gateway Failure. Request passed to redirector exceeds MAX_REDIRECTOR_REQUEST_STRLEN (" << MAX_REDIRECTOR_REQUEST_STRLEN << "). Request ABORTED.");
197 }
198
199 clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data;
200 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
201 assert (repContext);
202 Ip::Address tmpnoaddr;
203 tmpnoaddr.SetNoAddr();
204 repContext->setReplyToError(ERR_GATEWAY_FAILURE, status,
205 http->request->method, NULL,
206 http->getConn() != NULL && http->getConn()->clientConnection != NULL ?
207 http->getConn()->clientConnection->remote : tmpnoaddr,
208 http->request,
209 NULL,
210 #if USE_AUTH
211 http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
212 http->getConn()->auth_user_request : http->request->auth_user_request);
213 #else
214 NULL);
215 #endif
216
217 node = (clientStreamNode *)http->client_stream.tail->data;
218 clientStreamRead(node, http, node->readBuffer);
219 return;
220 }
221
222 debugs(61,6, HERE << "sending '" << buf << "' to the helper");
223 helperSubmit(redirectors, buf, redirectHandleReply, r);
224 }
225
226 static void
227 redirectRegisterWithCacheManager(void)
228 {
229 Mgr::RegisterAction("redirector", "URL Redirector Stats", redirectStats, 0, 1);
230 }
231
232 void
233 redirectInit(void)
234 {
235 static int init = 0;
236
237 redirectRegisterWithCacheManager();
238
239 if (!Config.Program.redirect)
240 return;
241
242 if (redirectors == NULL)
243 redirectors = new helper("redirector");
244
245 redirectors->cmdline = Config.Program.redirect;
246
247 redirectors->childs = Config.redirectChildren;
248
249 redirectors->ipc_type = IPC_STREAM;
250
251 helperOpenServers(redirectors);
252
253 if (!init) {
254 init = 1;
255 CBDATA_INIT_TYPE(redirectStateData);
256 }
257 }
258
259 void
260 redirectShutdown(void)
261 {
262 if (!redirectors)
263 return;
264
265 helperShutdown(redirectors);
266
267 if (!shutting_down)
268 return;
269
270 delete redirectors;
271 redirectors = NULL;
272 }