]> granicus.if.org Git - apache/blob - server/apreq_module_custom.c
avoid duplication of APR_HOOK_LINK invocations
[apache] / server / apreq_module_custom.c
1 /*
2 **  Licensed to the Apache Software Foundation (ASF) under one or more
3 ** contributor license agreements.  See the NOTICE file distributed with
4 ** this work for additional information regarding copyright ownership.
5 ** The ASF licenses this file to You under the Apache License, Version 2.0
6 ** (the "License"); you may not use this file except in compliance with
7 ** the License.  You may obtain a copy of the License at
8 **
9 **      http://www.apache.org/licenses/LICENSE-2.0
10 **
11 **  Unless required by applicable law or agreed to in writing, software
12 **  distributed under the License is distributed on an "AS IS" BASIS,
13 **  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 **  See the License for the specific language governing permissions and
15 **  limitations under the License.
16 */
17
18 #include "apr_strings.h"
19 #include "apreq_module.h"
20 #include "apreq_error.h"
21 #include "apreq_util.h"
22
23 #define READ_BYTES (64 * 1024)
24
25 struct custom_handle {
26     struct apreq_handle_t        handle;
27
28     apr_table_t                 *jar, *args, *body;
29     apr_status_t                 jar_status,
30                                  args_status,
31                                  body_status;
32
33     apreq_parser_t              *parser;
34
35     apr_uint64_t                 read_limit;
36     apr_uint64_t                 bytes_read;
37     apr_bucket_brigade          *in;
38     apr_bucket_brigade          *tmpbb;
39 };
40
41
42 static apr_status_t custom_parse_brigade(apreq_handle_t *handle, apr_uint64_t bytes)
43 {
44     struct custom_handle *req = (struct custom_handle *)handle;
45     apr_status_t s;
46     apr_bucket *e;
47
48     if (req->body_status != APR_INCOMPLETE)
49         return req->body_status;
50
51     switch (s = apr_brigade_partition(req->in, bytes, &e)) {
52         apr_off_t len;
53
54     case APR_SUCCESS:
55         apreq_brigade_move(req->tmpbb, req->in, e);
56         req->bytes_read += bytes;
57
58         if (req->bytes_read > req->read_limit) {
59             req->body_status = APREQ_ERROR_OVERLIMIT;
60             break;
61         }
62
63         req->body_status =
64             apreq_parser_run(req->parser, req->body, req->tmpbb);
65
66         apr_brigade_cleanup(req->tmpbb);
67         break;
68
69     case APR_INCOMPLETE:
70         apreq_brigade_move(req->tmpbb, req->in, e);
71         s = apr_brigade_length(req->tmpbb, 1, &len);
72         if (s != APR_SUCCESS) {
73             req->body_status = s;
74             break;
75         }
76         req->bytes_read += len;
77
78         if (req->bytes_read > req->read_limit) {
79             req->body_status = APREQ_ERROR_OVERLIMIT;
80             break;
81         }
82         req->body_status =
83             apreq_parser_run(req->parser, req->body, req->tmpbb);
84
85         apr_brigade_cleanup(req->tmpbb);
86         break;
87
88     default:
89         req->body_status = s;
90     }
91
92     return req->body_status;
93 }
94
95
96
97 static apr_status_t custom_jar(apreq_handle_t *handle, const apr_table_t **t)
98 {
99     struct custom_handle *req = (struct custom_handle *)handle;
100     *t = req->jar;
101     return req->jar_status;
102 }
103
104 static apr_status_t custom_args(apreq_handle_t *handle, const apr_table_t **t)
105 {
106     struct custom_handle *req = (struct custom_handle*)handle;
107     *t = req->args;
108     return req->args_status;
109 }
110
111 static apr_status_t custom_body(apreq_handle_t *handle, const apr_table_t **t)
112 {
113     struct custom_handle *req = (struct custom_handle*)handle;
114     while (req->body_status == APR_INCOMPLETE)
115         custom_parse_brigade(handle, READ_BYTES);
116     *t = req->body;
117     return req->body_status;
118 }
119
120
121
122 static apreq_cookie_t *custom_jar_get(apreq_handle_t *handle, const char *name)
123 {
124     struct custom_handle *req = (struct custom_handle*)handle;
125     const char *val;
126
127     if (req->jar == NULL || name == NULL)
128         return NULL;
129
130     val = apr_table_get(req->jar, name);
131
132     if (val == NULL)
133         return NULL;
134
135     return apreq_value_to_cookie(val);
136 }
137
138 static apreq_param_t *custom_args_get(apreq_handle_t *handle, const char *name)
139 {
140     struct custom_handle *req = (struct custom_handle*)handle;
141     const char *val;
142
143     if (req->args == NULL || name == NULL)
144         return NULL;
145
146     val = apr_table_get(req->args, name);
147
148     if (val == NULL)
149         return NULL;
150
151     return apreq_value_to_param(val);
152 }
153
154 static apreq_param_t *custom_body_get(apreq_handle_t *handle, const char *name)
155 {
156     struct custom_handle *req = (struct custom_handle*)handle;
157     const char *val;
158
159     if (req->body == NULL || name == NULL)
160         return NULL;
161
162     while (1) {
163         *(const char **)&val = apr_table_get(req->body, name);
164         if (val != NULL)
165             break;
166
167         if (req->body_status == APR_INCOMPLETE)
168             custom_parse_brigade(handle, READ_BYTES);
169         else
170             return NULL;
171     }
172
173     return apreq_value_to_param(val);
174 }
175
176
177
178 static apr_status_t custom_parser_get(apreq_handle_t *handle,
179                                       const apreq_parser_t **parser)
180 {
181     struct custom_handle *req = (struct custom_handle*)handle;
182     *parser = req->parser;
183
184     return APR_SUCCESS;
185 }
186
187 static apr_status_t custom_parser_set(apreq_handle_t *handle,
188                                       apreq_parser_t *parser)
189 {
190     (void)handle;
191     (void)parser;
192     return APR_ENOTIMPL;
193 }
194
195 static apr_status_t custom_hook_add(apreq_handle_t *handle,
196                                     apreq_hook_t *hook)
197 {
198     struct custom_handle *req = (struct custom_handle*)handle;
199     apreq_parser_add_hook(req->parser, hook);
200     return APR_SUCCESS;
201 }
202
203 static apr_status_t custom_brigade_limit_get(apreq_handle_t *handle,
204                                              apr_size_t *bytes)
205 {
206     struct custom_handle *req = (struct custom_handle*)handle;
207     *bytes = req->parser->brigade_limit;
208     return APR_SUCCESS;
209 }
210
211 static apr_status_t custom_brigade_limit_set(apreq_handle_t *handle,
212                                              apr_size_t bytes)
213 {
214     (void)handle;
215     (void)bytes;
216     return APR_ENOTIMPL;
217 }
218
219 static apr_status_t custom_read_limit_get(apreq_handle_t *handle,
220                                           apr_uint64_t *bytes)
221 {
222     struct custom_handle *req = (struct custom_handle*)handle;
223     *bytes = req->read_limit;
224     return APR_SUCCESS;
225 }
226
227 static apr_status_t custom_read_limit_set(apreq_handle_t *handle,
228                                           apr_uint64_t bytes)
229 {
230     (void)handle;
231     (void)bytes;
232     return APR_ENOTIMPL;
233 }
234
235 static apr_status_t custom_temp_dir_get(apreq_handle_t *handle,
236                                         const char **path)
237 {
238     struct custom_handle *req = (struct custom_handle*)handle;
239
240     *path = req->parser->temp_dir;
241     return APR_SUCCESS;
242 }
243
244 static apr_status_t custom_temp_dir_set(apreq_handle_t *handle,
245                                         const char *path)
246 {
247     (void)handle;
248     (void)path;
249     return APR_ENOTIMPL;
250 }
251
252
253 static APREQ_MODULE(custom, 20070428);
254
255 APREQ_DECLARE(apreq_handle_t *)apreq_handle_custom(apr_pool_t *pool,
256                                                    const char *query_string,
257                                                    const char *cookie,
258                                                    apreq_parser_t *parser,
259                                                    apr_uint64_t read_limit,
260                                                    apr_bucket_brigade *in)
261 {
262     struct custom_handle *req;
263     req = apr_palloc(pool, sizeof(*req));
264     req->handle.module = &custom_module;
265     req->handle.pool = pool;
266     req->handle.bucket_alloc = in->bucket_alloc;
267     req->read_limit = read_limit;
268     req->bytes_read = 0;
269     req->parser = parser;
270     req->in = apr_brigade_create(pool, in->bucket_alloc);
271     req->tmpbb = apr_brigade_create(pool, in->bucket_alloc);
272     req->body = apr_table_make(pool, APREQ_DEFAULT_NELTS);
273     req->body_status = APR_INCOMPLETE;
274     APR_BRIGADE_CONCAT(req->in, in);
275
276     if (cookie != NULL) {
277         req->jar = apr_table_make(pool, APREQ_DEFAULT_NELTS);
278         req->jar_status =
279             apreq_parse_cookie_header(pool, req->jar, cookie);
280     }
281     else {
282         req->jar = NULL;
283         req->jar_status = APREQ_ERROR_NODATA;
284     }
285
286
287     if (query_string != NULL) {
288         req->args = apr_table_make(pool, APREQ_DEFAULT_NELTS);
289         req->args_status =
290             apreq_parse_query_string(pool, req->args, query_string);
291     }
292     else {
293         req->args = NULL;
294         req->args_status = APREQ_ERROR_NODATA;
295     }
296
297     if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(req->in))) {
298         apr_bucket *eos = apr_bucket_eos_create(in->bucket_alloc);
299         APR_BRIGADE_INSERT_TAIL(req->in, eos);
300     }
301
302     return &req->handle;
303 }
304