libfast: cancel thread if it fails to accept fcgi sessions
[strongswan.git] / src / libfast / fast_session.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #define _GNU_SOURCE
17
18 #include "fast_session.h"
19
20 #include <string.h>
21 #include <fcgiapp.h>
22 #include <stdio.h>
23
24 #include <collections/linked_list.h>
25
26 #define COOKIE_LEN 16
27
28 typedef struct private_fast_session_t private_fast_session_t;
29
30 /**
31 * private data of the task manager
32 */
33 struct private_fast_session_t {
34
35 /**
36 * public functions
37 */
38 fast_session_t public;
39
40 /**
41 * session ID
42 */
43 char sid[COOKIE_LEN * 2 + 1];
44
45 /**
46 * have we sent the session cookie?
47 */
48 bool cookie_sent;
49
50 /**
51 * list of controller instances controller_t
52 */
53 linked_list_t *controllers;
54
55 /**
56 * list of filter instances filter_t
57 */
58 linked_list_t *filters;
59
60 /**
61 * user defined session context
62 */
63 fast_context_t *context;
64 };
65
66 METHOD(fast_session_t, add_controller, void,
67 private_fast_session_t *this, fast_controller_t *controller)
68 {
69 this->controllers->insert_last(this->controllers, controller);
70 }
71
72 METHOD(fast_session_t, add_filter, void,
73 private_fast_session_t *this, fast_filter_t *filter)
74 {
75 this->filters->insert_last(this->filters, filter);
76 }
77
78 /**
79 * Create a session ID and a cookie
80 */
81 static bool create_sid(private_fast_session_t *this)
82 {
83 char buf[COOKIE_LEN];
84 rng_t *rng;
85
86 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
87 if (!rng)
88 {
89 return FALSE;
90 }
91 if (!rng->get_bytes(rng, sizeof(buf), buf))
92 {
93 rng->destroy(rng);
94 return FALSE;
95 }
96 rng->destroy(rng);
97 chunk_to_hex(chunk_create(buf, sizeof(buf)), this->sid, FALSE);
98 return TRUE;
99 }
100
101 /**
102 * run all registered filters
103 */
104 static bool run_filter(private_fast_session_t *this, fast_request_t *request,
105 char *p0, char *p1, char *p2, char *p3, char *p4, char *p5)
106 {
107 enumerator_t *enumerator;
108 fast_filter_t *filter;
109
110 enumerator = this->filters->create_enumerator(this->filters);
111 while (enumerator->enumerate(enumerator, &filter))
112 {
113 if (!filter->run(filter, request, p0, p1, p2, p3, p4, p5))
114 {
115 enumerator->destroy(enumerator);
116 return FALSE;
117 }
118 }
119 enumerator->destroy(enumerator);
120 return TRUE;
121 }
122
123 METHOD(fast_session_t, process, void,
124 private_fast_session_t *this, fast_request_t *request)
125 {
126 char *pos, *start, *param[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
127 enumerator_t *enumerator;
128 bool handled = FALSE;
129 fast_controller_t *current;
130 int i = 0;
131
132 if (!this->cookie_sent)
133 {
134 request->add_cookie(request, "SID", this->sid);
135 this->cookie_sent = TRUE;
136 }
137
138 start = request->get_path(request);
139 if (start)
140 {
141 if (*start == '/')
142 {
143 start++;
144 }
145 while ((pos = strchr(start, '/')) != NULL && i < 5)
146 {
147 param[i++] = strndupa(start, pos - start);
148 start = pos + 1;
149 }
150 param[i] = strdupa(start);
151
152 if (run_filter(this, request, param[0], param[1], param[2], param[3],
153 param[4], param[5]))
154 {
155 enumerator = this->controllers->create_enumerator(this->controllers);
156 while (enumerator->enumerate(enumerator, &current))
157 {
158 if (streq(current->get_name(current), param[0]))
159 {
160 current->handle(current, request, param[1], param[2],
161 param[3], param[4], param[5]);
162 handled = TRUE;
163 break;
164 }
165 }
166 enumerator->destroy(enumerator);
167 }
168 else
169 {
170 handled = TRUE;
171 }
172 }
173 if (!handled)
174 {
175 if (this->controllers->get_first(this->controllers,
176 (void**)&current) == SUCCESS)
177 {
178 request->streamf(request,
179 "Status: 301 Moved permanently\nLocation: %s/%s\n\n",
180 request->get_base(request), current->get_name(current));
181 }
182 }
183 }
184
185 METHOD(fast_session_t, get_sid, char*,
186 private_fast_session_t *this)
187 {
188 return this->sid;
189 }
190
191 METHOD(fast_session_t, destroy, void,
192 private_fast_session_t *this)
193 {
194 this->controllers->destroy_offset(this->controllers,
195 offsetof(fast_controller_t, destroy));
196 this->filters->destroy_offset(this->filters,
197 offsetof(fast_filter_t, destroy));
198 DESTROY_IF(this->context);
199 free(this);
200 }
201
202 /*
203 * see header file
204 */
205 fast_session_t *fast_session_create(fast_context_t *context)
206 {
207 private_fast_session_t *this;
208
209 INIT(this,
210 .public = {
211 .add_controller = _add_controller,
212 .add_filter = _add_filter,
213 .process = _process,
214 .get_sid = _get_sid,
215 .destroy = _destroy,
216 },
217 .controllers = linked_list_create(),
218 .filters = linked_list_create(),
219 .context = context,
220 );
221 if (!create_sid(this))
222 {
223 destroy(this);
224 return NULL;
225 }
226
227 return &this->public;
228 }