/src/httpd/include/apreq_parser.h
Line | Count | Source |
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 | | #ifndef APREQ_PARSERS_H |
19 | | #define APREQ_PARSERS_H |
20 | | /* These structs are defined below */ |
21 | | |
22 | | #include "apreq_param.h" |
23 | | |
24 | | #ifdef __cplusplus |
25 | | extern "C" { |
26 | | #endif /* __cplusplus */ |
27 | | |
28 | | /** |
29 | | * @file apreq_parser.h |
30 | | * @brief Request body parser API |
31 | | * @ingroup libapreq2 |
32 | | */ |
33 | | |
34 | | /** |
35 | | * A hook is called by the parser whenever data arrives in a file |
36 | | * upload parameter of the request body. You may associate any number |
37 | | * of hooks with a parser instance with apreq_parser_add_hook(). |
38 | | */ |
39 | | typedef struct apreq_hook_t apreq_hook_t; |
40 | | |
41 | | /** |
42 | | * A request body parser instance. |
43 | | */ |
44 | | typedef struct apreq_parser_t apreq_parser_t; |
45 | | |
46 | | /** Parser arguments. */ |
47 | | #define APREQ_PARSER_ARGS apreq_parser_t *parser, \ |
48 | | apr_table_t *t, \ |
49 | | apr_bucket_brigade *bb |
50 | | |
51 | | /** Hook arguments */ |
52 | | #define APREQ_HOOK_ARGS apreq_hook_t *hook, \ |
53 | | apreq_param_t *param, \ |
54 | | apr_bucket_brigade *bb |
55 | | |
56 | | /** |
57 | | * The callback function implementing a request body parser. |
58 | | */ |
59 | | typedef apr_status_t (*apreq_parser_function_t)(APREQ_PARSER_ARGS); |
60 | | |
61 | | /** |
62 | | * The callback function of a hook. See apreq_hook_t. |
63 | | */ |
64 | | typedef apr_status_t (*apreq_hook_function_t)(APREQ_HOOK_ARGS); |
65 | | |
66 | | /** |
67 | | * Declares a API parser. |
68 | | */ |
69 | | #define APREQ_DECLARE_PARSER(f) APREQ_DECLARE_NONSTD(apr_status_t) \ |
70 | | f (APREQ_PARSER_ARGS) |
71 | | |
72 | | /** |
73 | | * Declares an API hook. |
74 | | */ |
75 | | #define APREQ_DECLARE_HOOK(f) APREQ_DECLARE_NONSTD(apr_status_t) \ |
76 | | f (APREQ_HOOK_ARGS) |
77 | | |
78 | | /** |
79 | | * A hook is called by the parser whenever data arrives in a file |
80 | | * upload parameter of the request body. You may associate any number |
81 | | * of hooks with a parser instance with apreq_parser_add_hook(). |
82 | | */ |
83 | | struct apreq_hook_t { |
84 | | apreq_hook_function_t hook; /**< the hook function */ |
85 | | apreq_hook_t *next; /**< next item in the linked list */ |
86 | | apr_pool_t *pool; /**< pool which allocated this hook */ |
87 | | void *ctx; /**< a user defined pointer passed to the hook function */ |
88 | | }; |
89 | | |
90 | | /** |
91 | | * A request body parser instance. |
92 | | */ |
93 | | struct apreq_parser_t { |
94 | | /** the function which parses chunks of body data */ |
95 | | apreq_parser_function_t parser; |
96 | | /** the Content-Type request header */ |
97 | | const char *content_type; |
98 | | /** a pool which outlasts the bucket_alloc. */ |
99 | | apr_pool_t *pool; |
100 | | /** bucket allocator used to create bucket brigades */ |
101 | | apr_bucket_alloc_t *bucket_alloc; |
102 | | /** the maximum in-memory bytes a brigade may use */ |
103 | | apr_size_t brigade_limit; |
104 | | /** the directory for generating temporary files */ |
105 | | const char *temp_dir; |
106 | | /** linked list of hooks */ |
107 | | apreq_hook_t *hook; |
108 | | /** internal context pointer used by the parser function */ |
109 | | void *ctx; |
110 | | }; |
111 | | |
112 | | |
113 | | /** |
114 | | * Parse the incoming brigade into a table. Parsers normally |
115 | | * consume all the buckets of the brigade during parsing. However |
116 | | * parsers may leave "rejected" data in the brigade, even during a |
117 | | * successful parse, so callers may need to clean up the brigade |
118 | | * themselves (in particular, rejected buckets should not be |
119 | | * passed back to the parser again). |
120 | | * @remark bb == NULL is valid: the parser should return its |
121 | | * public status: APR_INCOMPLETE, APR_SUCCESS, or an error code. |
122 | | */ |
123 | | static APR_INLINE |
124 | | apr_status_t apreq_parser_run(struct apreq_parser_t *psr, apr_table_t *t, |
125 | | apr_bucket_brigade *bb) |
126 | 999 | { |
127 | 999 | return psr->parser(psr, t, bb); |
128 | 999 | } Unexecuted instantiation: fuzz_preq.c:apreq_parser_run Unexecuted instantiation: apreq_parser.c:apreq_parser_run apreq_parser_multipart.c:apreq_parser_run Line | Count | Source | 126 | 999 | { | 127 | 999 | return psr->parser(psr, t, bb); | 128 | 999 | } |
Unexecuted instantiation: apreq_parser_urlencoded.c:apreq_parser_run Unexecuted instantiation: apreq_parser_header.c:apreq_parser_run |
129 | | |
130 | | /** |
131 | | * Run the hook with the current parameter and the incoming |
132 | | * bucket brigade. The hook may modify the brigade if necessary. |
133 | | * Once all hooks have completed, the contents of the brigade will |
134 | | * be added to the parameter's bb attribute. |
135 | | * @return APR_SUCCESS on success. All other values represent errors. |
136 | | */ |
137 | | static APR_INLINE |
138 | | apr_status_t apreq_hook_run(struct apreq_hook_t *h, apreq_param_t *param, |
139 | | apr_bucket_brigade *bb) |
140 | 1.14k | { |
141 | 1.14k | return h->hook(h, param, bb); |
142 | 1.14k | } Unexecuted instantiation: fuzz_preq.c:apreq_hook_run Unexecuted instantiation: apreq_parser.c:apreq_hook_run apreq_parser_multipart.c:apreq_hook_run Line | Count | Source | 140 | 641 | { | 141 | 641 | return h->hook(h, param, bb); | 142 | 641 | } |
apreq_parser_urlencoded.c:apreq_hook_run Line | Count | Source | 140 | 500 | { | 141 | 500 | return h->hook(h, param, bb); | 142 | 500 | } |
Unexecuted instantiation: apreq_parser_header.c:apreq_hook_run |
143 | | |
144 | | |
145 | | /** |
146 | | * RFC 822 Header parser. It will reject all data |
147 | | * after the first CRLF CRLF sequence (an empty line). |
148 | | * See apreq_parser_run() for more info on rejected data. |
149 | | */ |
150 | | APREQ_DECLARE_PARSER(apreq_parse_headers); |
151 | | |
152 | | /** |
153 | | * RFC 2396 application/x-www-form-urlencoded parser. |
154 | | */ |
155 | | APREQ_DECLARE_PARSER(apreq_parse_urlencoded); |
156 | | |
157 | | /** |
158 | | * RFC 2388 multipart/form-data (and XForms 1.0 multipart/related) |
159 | | * parser. It will reject any buckets representing preamble and |
160 | | * postamble text (this is normal behavior, not an error condition). |
161 | | * See apreq_parser_run() for more info on rejected data. |
162 | | */ |
163 | | APREQ_DECLARE_PARSER(apreq_parse_multipart); |
164 | | |
165 | | /** |
166 | | * Generic parser. No table entries will be added to |
167 | | * the req->body table by this parser. The parser creates |
168 | | * a dummy apreq_param_t to pass to any configured hooks. If |
169 | | * no hooks are configured, the dummy param's bb slot will |
170 | | * contain a copy of the request body. It can be retrieved |
171 | | * by casting the parser's ctx pointer to (apreq_param_t **). |
172 | | */ |
173 | | APREQ_DECLARE_PARSER(apreq_parse_generic); |
174 | | |
175 | | /** |
176 | | * apr_xml_parser hook. It will parse until EOS appears. |
177 | | * The parsed document isn't available until parsing has |
178 | | * completed successfully. The hook's ctx pointer may |
179 | | * be cast as (apr_xml_doc **) to retrieve the |
180 | | * parsed document. |
181 | | */ |
182 | | APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser); |
183 | | |
184 | | /** |
185 | | * Construct a parser. |
186 | | * |
187 | | * @param pool Pool used to allocate the parser. |
188 | | * @param ba bucket allocator used to create bucket brigades |
189 | | * @param content_type Content-type that this parser can deal with. |
190 | | * @param pfn The parser function. |
191 | | * @param brigade_limit the maximum in-memory bytes a brigade may use |
192 | | * @param temp_dir the directory used by the parser for temporary files |
193 | | * @param hook Hooks to associate this parser with. |
194 | | * @param ctx Parser's internal scratch pad. |
195 | | * @return New parser. |
196 | | */ |
197 | | APREQ_DECLARE(apreq_parser_t *) apreq_parser_make(apr_pool_t *pool, |
198 | | apr_bucket_alloc_t *ba, |
199 | | const char *content_type, |
200 | | apreq_parser_function_t pfn, |
201 | | apr_size_t brigade_limit, |
202 | | const char *temp_dir, |
203 | | apreq_hook_t *hook, |
204 | | void *ctx); |
205 | | |
206 | | /** |
207 | | * Construct a hook. |
208 | | * |
209 | | * @param pool used to allocate the hook. |
210 | | * @param hook The hook function. |
211 | | * @param next List of other hooks for this hook to call on. |
212 | | * @param ctx Hook's internal scratch pad. |
213 | | * @return New hook. |
214 | | */ |
215 | | APREQ_DECLARE(apreq_hook_t *) apreq_hook_make(apr_pool_t *pool, |
216 | | apreq_hook_function_t hook, |
217 | | apreq_hook_t *next, |
218 | | void *ctx); |
219 | | |
220 | | |
221 | | /** |
222 | | * Add a new hook to the end of the parser's hook list. |
223 | | * |
224 | | * @param p Parser. |
225 | | * @param h Hook to append. |
226 | | */ |
227 | | APREQ_DECLARE(apr_status_t) apreq_parser_add_hook(apreq_parser_t *p, |
228 | | apreq_hook_t *h); |
229 | | |
230 | | |
231 | | /** |
232 | | * Fetch the default parser function associated with the given MIME type. |
233 | | * @param enctype The desired enctype (can also be a full "Content-Type" |
234 | | * header). |
235 | | * @return The parser function, or NULL if the enctype is unrecognized. |
236 | | */ |
237 | | APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype); |
238 | | |
239 | | |
240 | | /** |
241 | | * Register a new parsing function with a MIME enctype. |
242 | | * Registered parsers are added to apreq_parser()'s |
243 | | * internal lookup table. |
244 | | * |
245 | | * @param enctype The MIME type. |
246 | | * @param pfn The function to use during parsing. Setting |
247 | | * parser == NULL will remove an existing parser. |
248 | | * |
249 | | * @return APR_SUCCESS or error. |
250 | | */ |
251 | | |
252 | | APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype, |
253 | | apreq_parser_function_t pfn); |
254 | | |
255 | | |
256 | | /** |
257 | | * Returns APREQ_ERROR_GENERAL. Effectively disables mfd parser |
258 | | * if a file-upload field is present. |
259 | | * |
260 | | */ |
261 | | APREQ_DECLARE_HOOK(apreq_hook_disable_uploads); |
262 | | |
263 | | /** |
264 | | * Calls apr_brigade_cleanup on the incoming brigade |
265 | | * after passing the brigade to any subsequent hooks. |
266 | | */ |
267 | | APREQ_DECLARE_HOOK(apreq_hook_discard_brigade); |
268 | | |
269 | | /** |
270 | | * Context struct for the apreq_hook_find_param hook. |
271 | | */ |
272 | | typedef struct apreq_hook_find_param_ctx_t { |
273 | | const char *name; |
274 | | apreq_param_t *param; |
275 | | apreq_hook_t *prev; |
276 | | } apreq_hook_find_param_ctx_t; |
277 | | |
278 | | |
279 | | /** |
280 | | * Special purpose utility for locating a parameter |
281 | | * during parsing. The hook's ctx should be initialized |
282 | | * to an apreq_hook_find_param_ctx_t *, with the name |
283 | | * attribute set to the sought parameter name, the param |
284 | | * attribute set to NULL, and the prev attribute set to |
285 | | * the address of the previous hook. The param attribute |
286 | | * will be reassigned to the first param found, and once |
287 | | * that happens this hook is immediately removed from the chain. |
288 | | * |
289 | | * @remarks When used, this should always be the first hook |
290 | | * invoked, so add it manually with ctx->prev = &parser->hook |
291 | | * instead of using apreq_parser_add_hook. |
292 | | */ |
293 | | APREQ_DECLARE_HOOK(apreq_hook_find_param); |
294 | | |
295 | | |
296 | | #ifdef __cplusplus |
297 | | } |
298 | | |
299 | | #endif |
300 | | #endif /* APREQ_PARSERS_H */ |