tinyows 1.2.2
ows_request.c
Go to the documentation of this file.
1/*
2 Copyright (c) <2007-2012> <Barbara Philippot - Olivier Courtin>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 IN THE SOFTWARE.
21*/
22
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <assert.h>
27#include <string.h>
28#include <ctype.h>
29#include <libxml/xmlschemas.h>
30#include <libxml/xmlschemastypes.h>
31
32#include "ows.h"
33#include "../ows_define.h"
34
35
36/*
37 * Initialize ows_request structure
38 */
40{
41 ows_request *or;
42 or = malloc(sizeof(ows_request));
43 assert(or);
44
45 or->version = NULL;
48 or->request.wfs = NULL;
49
50 return or;
51}
52
53
54/*
55 * Release ows_request structure
56 */
58{
59 assert(or);
60
61 if (or->version) ows_version_free(or->version);
62
63 switch (or->service) {
64 case WFS:
66 break;
68 break;
69 default:
70 assert(0); /* Should not happen */
71 }
72
73 free(or);
74 or = NULL;
75}
76
77
78#ifdef OWS_DEBUG
79/*
80 * Flush an ows_request structure
81 * Used for debug purpose
82 */
83void ows_request_flush(ows_request * or, FILE * output)
84{
85 assert(or);
86 assert(output);
87
88 fprintf(output, "method:%d\n", or->method);
89 fprintf(output, "service:%d\n", or->service);
90
91 if (or->version) {
92 fprintf(output, "version:");
93 ows_version_flush(or->version, output);
94 fprintf(output, "\n");
95 }
96}
97#endif
98
99
100/*
101 * Simple callback used to catch error and warning from libxml2 schema
102 * validation
103 */
104static void libxml2_callback (void * ctx, const char * msg, ...)
105{
106 va_list varg;
107 char * str;
108 ows *o;
109
110 o = (ows *) ctx;
111 va_start(varg, msg);
112 str = (char *)va_arg( varg, char *);
113 ows_log(o, 1, str);
114
115#ifdef OWS_DEBUG
116 fprintf(stderr, "%s", str);
117#endif
118}
119
120
121static xmlSchemaPtr ows_generate_schema(const ows *o, buffer * xml_schema, bool schema_is_file)
122{
123 xmlSchemaParserCtxtPtr ctxt;
124 xmlSchemaPtr schema = NULL;
125
126 assert(o);
127 assert(xml_schema);
128
129 /* Open XML Schema File */
130 if (schema_is_file) ctxt = xmlSchemaNewParserCtxt(xml_schema->buf);
131 else ctxt = xmlSchemaNewMemParserCtxt(xml_schema->buf, xml_schema->use);
132
133 xmlSchemaSetParserErrors(ctxt,
134 (xmlSchemaValidityErrorFunc) libxml2_callback,
135 (xmlSchemaValidityWarningFunc) libxml2_callback,
136 (void *) o);
137
138 schema = xmlSchemaParse(ctxt);
139 xmlSchemaFreeParserCtxt(ctxt);
140
141 /* If XML Schema hasn't been rightly loaded */
142 if (!schema) {
143 xmlSchemaCleanupTypes();
144 return NULL;
145 }
146
147 return schema;
148}
149
150
151/*
152 * Valid an xml string against an XML schema
153 */
154int ows_schema_validation(ows *o, buffer *xml_schema, buffer *xml, bool schema_is_file, enum ows_schema_type schema_type)
155{
156 xmlSchemaPtr schema;
157 xmlSchemaValidCtxtPtr schema_ctx;
158 xmlDocPtr doc;
159 int ret = -1;
160 bool schema_generate = true;
161
162 assert(o);
163 assert(xml);
164 assert(xml_schema);
165
166 doc = xmlParseMemory(xml->buf, xml->use);
167 if (!doc) return ret;
168 if (!ows_libxml_check_namespace(o, doc->children)) {
169 xmlFreeDoc(doc);
170 return ret;
171 }
172
173 if (schema_type == WFS_SCHEMA_TYPE_100 && o->schema_wfs_100) {
174 schema_generate = false;
175 schema = o->schema_wfs_100;
176 } else if (schema_type == WFS_SCHEMA_TYPE_110 && o->schema_wfs_110) {
177 schema_generate = false;
178 schema = o->schema_wfs_110;
179 }
180
181 if (schema_generate) schema = ows_generate_schema(o, xml_schema, schema_is_file);
182 if (!schema) {
183 xmlFreeDoc(doc);
184 return ret;
185 }
186
187 schema_ctx = xmlSchemaNewValidCtxt(schema);
188 xmlSchemaSetValidErrors(schema_ctx,
189 (xmlSchemaValidityErrorFunc) libxml2_callback,
190 (xmlSchemaValidityWarningFunc) libxml2_callback, (void *) o);
191 if (schema_ctx) {
192 ret = xmlSchemaValidateDoc(schema_ctx, doc); /* validation */
193 xmlSchemaFreeValidCtxt(schema_ctx);
194 }
195 xmlFreeDoc(doc);
196
197 if (schema_generate) {
198 if (schema_type == WFS_SCHEMA_TYPE_100) o->schema_wfs_100 = schema;
199 else if (schema_type == WFS_SCHEMA_TYPE_110) o->schema_wfs_110 = schema;
200 }
201
202 return ret;
203}
204
205
206/*
207 * Check and fill version
208 */
210{
211 buffer *b;
212 ows_version *v;
213 list *l = NULL;
214
215 assert(o);
216 assert(or);
217 assert(cgi);
218
219 v = or->version;
220 b = array_get(cgi, "version");
221
222 if (buffer_cmp(b, "")) ows_version_set(o->request->version, 0, 0, 0);
223 else {
224 /* check if version format is x.y.z */
225 if (b->use < 5) {
227 "VERSION parameter is not valid (use x.y.z)", "version");
228 return v;
229 }
230
231 l = list_explode('.', b);
232 if (l->size != 3) {
233 list_free(l);
235 "VERSION parameter is not valid (use x.y.z)", "version");
236 return v;
237 }
238
239 if ( check_regexp(l->first->value->buf, "^[0-9]+$")
240 && check_regexp(l->first->next->value->buf, "^[0-9]+$")
241 && check_regexp(l->first->next->next->value->buf, "^[0-9]+$")) {
242 v->major = atoi(l->first->value->buf);
243 v->minor = atoi(l->first->next->value->buf);
244 v->release = atoi(l->first->next->next->value->buf);
245 } else {
246 list_free(l);
248 "VERSION parameter is not valid (use x.y.z)", "version");
249 return v;
250 }
251
252 list_free(l);
253 }
254
255 return v;
256}
257
258
259/*
260 * Check common OWS parameters's validity
261 *(service, version, request and layers definition)
262 */
263void ows_request_check(ows * o, ows_request * or, const array * cgi, const char *query)
264{
265 list_node *srid;
266 buffer *typename, *xmlstring, *schema, *b=NULL;
267 ows_layer_node *ln = NULL;
268 bool srsname = false;
269 int valid = 0;
270
271 assert(o && or && cgi && query);
272
273 /* check if SERVICE is set */
274 if (!array_is_key(cgi, "service")) {
275 /* Tests WFS 1.1.0 require a default value for requests
276 encoded in XML if service is not set */
277 if (cgi_method_get()) {
278 ows_error(o, OWS_ERROR_MISSING_PARAMETER_VALUE, "SERVICE is not set", "SERVICE");
279 return;
280 } else {
281 if (buffer_case_cmp(o->metadata->type, "WFS"))
282 or->service = WFS;
283 else {
284 ows_error(o, OWS_ERROR_INVALID_PARAMETER_VALUE, "SERVICE Unknown", "SERVICE");
285 return;
286 }
287 }
288 } else {
289 b = array_get(cgi, "service");
290
291 if (buffer_case_cmp(b, "WFS"))
292 or->service = WFS;
293 else if (buffer_case_cmp(b, "")) {
294 if (buffer_case_cmp(o->metadata->type, "WFS"))
295 or->service = WFS;
296 else {
297 ows_error(o, OWS_ERROR_INVALID_PARAMETER_VALUE, "SERVICE Unknown", "SERVICE");
298 return;
299 }
300 } else {
301 ows_error(o, OWS_ERROR_INVALID_PARAMETER_VALUE, "SERVICE unknown", "SERVICE");
302 return;
303 }
304 }
305
306
307 /* check if REQUEST is set */
308 if (!array_is_key(cgi, "request")) {
309 ows_error(o, OWS_ERROR_MISSING_PARAMETER_VALUE, "REQUEST is not set", "REQUEST");
310 return;
311 } else b = array_get(cgi, "request");
312
313 /* check if VERSION is set and init Version */
315
316 if (!array_is_key(cgi, "version") || buffer_cmp(array_get(cgi, "version"), "")) {
317 if (!buffer_case_cmp(b, "GetCapabilities")) {
318 /* WFS 1.1.0 with KVP need a version set */
319 if (o->request->method == OWS_METHOD_KVP) {
320 ows_error(o, OWS_ERROR_MISSING_PARAMETER_VALUE, "VERSION is not set", "VERSION");
321 return;
322 }
323 /* WFS 1.1.0 require a default value for requests
324 encoded in XML if version is not set */
325 else if (o->request->method == OWS_METHOD_XML) {
326 if (or->service == WFS) ows_version_set(o->request->version, 1, 1, 0);
327 }
328 }
329 } else or->version = ows_request_check_version(o, or, cgi);
330
331 /* check if layers have name or title and srs */
332 for (ln = o->layers->first ; ln ; ln = ln->next) {
333
334 if (!ln->layer->name) {
335 ows_error(o, OWS_ERROR_CONFIG_FILE, "No layer name defined", "config_file");
336 return;
337 }
338
339 if (!ows_layer_match_table(o, ln->layer->name)) continue;
340
341 if (!ln->layer->title) {
342 ows_error(o, OWS_ERROR_CONFIG_FILE, "No layer title defined", "config_file");
343 return;
344 }
345
346 if (or->service == WFS) {
347 if (!ln->layer->ns_prefix->use) {
348 ows_error(o, OWS_ERROR_CONFIG_FILE, "No layer NameSpace prefix defined", "config_file");
349 return;
350 }
351
352 if (!ln->layer->ns_uri->use) {
353 ows_error(o, OWS_ERROR_CONFIG_FILE, "No layer NameSpace URI defined", "config_file");
354 return;
355 }
356 }
357
358 if (ln->layer->srid) {
359 if (array_is_key(cgi, "srsname") && array_is_key(cgi, "typename")) {
360 b = array_get(cgi, "srsname");
361 typename = array_get(cgi, "typename");
362
363 if (buffer_cmp(typename, ln->layer->name->buf)) {
364 if ( !check_regexp(b->buf, "^http://www.opengis.net")
365 && !check_regexp(b->buf, "^EPSG")
366 && !check_regexp(b->buf, "^urn:")
367 && !check_regexp(b->buf, "^spatialreferencing.org")) {
368 ows_error(o, OWS_ERROR_CONFIG_FILE, "srsname isn't valid", "srsName");
369 return;
370 }
371
372 for (srid = ln->layer->srid->first ; srid ; srid = srid->next) {
373 if (check_regexp(b->buf, srid->value->buf)) srsname = true;
374 }
375
376 if (srsname == false) {
377 ows_error(o, OWS_ERROR_CONFIG_FILE, "srsname doesn't match srid", "config_file");
378 return;
379 }
380 }
381 }
382 }
383 }
384
385 /* check XML Validity */
386 if ( (cgi_method_post() && ( !strcmp(getenv("CONTENT_TYPE"), "application/xml; charset=UTF-8")
387 || !strcmp(getenv("CONTENT_TYPE"), "application/xml")
388 || !strcmp(getenv("CONTENT_TYPE"), "text/xml")
389 || !strcmp(getenv("CONTENT_TYPE"), "text/plain")))
390 || (!cgi_method_post() && !cgi_method_get() && query[0] == '<') /* Unit test command line use case */ ) {
391
392 if (or->service == WFS && o->check_schema) {
393 xmlstring = buffer_from_str(query);
394
395 if (ows_version_get(or->version) == 100) {
396 schema = wfs_generate_schema(o, or->version);
397 valid = ows_schema_validation(o, schema, xmlstring, false, WFS_SCHEMA_TYPE_100);
398 } else {
399 schema = wfs_generate_schema(o, or->version);
400 valid = ows_schema_validation(o, schema, xmlstring, false, WFS_SCHEMA_TYPE_110);
401 }
402
403 buffer_free(schema);
404 buffer_free(xmlstring);
405
406 if (valid != 0) {
407 ows_error(o, OWS_ERROR_INVALID_PARAMETER_VALUE, "XML request isn't valid", "request");
408 return;
409 }
410 }
411 }
412}
void ows_log(ows *o, int log_level, const char *log)
Definition ows.c:235
int ows_version_get(ows_version *v)
void ows_version_flush(ows_version *v, FILE *output)
buffer * wfs_generate_schema(ows *o, ows_version *version)
bool buffer_cmp(const buffer *buf, const char *str)
Definition buffer.c:290
bool cgi_method_get()
Definition cgi_request.c:42
void list_free(list *l)
Definition list.c:54
void wfs_request_free(wfs_request *wr)
bool cgi_method_post()
Definition cgi_request.c:55
bool buffer_case_cmp(const buffer *buf, const char *str)
Definition buffer.c:330
bool ows_layer_match_table(const ows *o, const buffer *name)
Definition ows_layer.c:84
buffer * array_get(const array *a, const char *key)
Definition array.c:147
void ows_error(ows *o, enum ows_error_code code, char *message, char *locator)
Definition ows_error.c:71
ows_version * ows_version_init()
Definition ows_version.c:33
bool ows_libxml_check_namespace(ows *o, xmlNodePtr n)
Definition ows_libxml.c:67
bool array_is_key(const array *a, const char *key)
Definition array.c:105
buffer * buffer_from_str(const char *str)
Definition buffer.c:202
void buffer_free(buffer *buf)
Definition buffer.c:83
void ows_version_set(ows_version *v, int major, int minor, int release)
Definition ows_version.c:51
list * list_explode(char separator, const buffer *value)
Definition list.c:296
void ows_request_flush(ows_request *or, FILE *output)
bool check_regexp(const char *str_request, const char *str_regex)
Definition regexp.c:36
void ows_version_free(ows_version *v)
Definition ows_version.c:94
static ows_version * ows_request_check_version(ows *o, ows_request *or, const array *cgi)
void ows_request_check(ows *o, ows_request *or, const array *cgi, const char *query)
void ows_request_free(ows_request *or)
Definition ows_request.c:57
static void libxml2_callback(void *ctx, const char *msg,...)
ows_request * ows_request_init()
Definition ows_request.c:39
static xmlSchemaPtr ows_generate_schema(const ows *o, buffer *xml_schema, bool schema_is_file)
int ows_schema_validation(ows *o, buffer *xml_schema, buffer *xml, bool schema_is_file, enum ows_schema_type schema_type)
@ OWS_METHOD_KVP
Definition ows_struct.h:248
@ OWS_METHOD_UNKNOWN
Definition ows_struct.h:247
@ OWS_METHOD_XML
Definition ows_struct.h:249
@ OWS_ERROR_MISSING_PARAMETER_VALUE
Definition ows_struct.h:158
@ OWS_ERROR_INVALID_PARAMETER_VALUE
Definition ows_struct.h:159
@ OWS_ERROR_CONFIG_FILE
Definition ows_struct.h:165
ows_schema_type
Definition ows_struct.h:295
@ WFS_SCHEMA_TYPE_110
Definition ows_struct.h:297
@ WFS_SCHEMA_TYPE_100
Definition ows_struct.h:296
@ OWS_SERVICE_UNKNOWN
Definition ows_struct.h:243
@ WFS
Definition ows_struct.h:242
char * buf
size to next realloc
Definition ows_struct.h:39
size_t use
Definition ows_struct.h:36
struct List_node * next
Definition ows_struct.h:45
buffer * value
Definition ows_struct.h:44
unsigned int size
Definition ows_struct.h:52
list_node * first
Definition ows_struct.h:50
ows_layer_node * first
Definition ows_struct.h:205
ows_layer * layer
Definition ows_struct.h:199
struct Ows_layer_node * next
Definition ows_struct.h:200
list * srid
Definition ows_struct.h:183
buffer * name
Definition ows_struct.h:177
buffer * ns_uri
Definition ows_struct.h:193
buffer * ns_prefix
Definition ows_struct.h:192
buffer * title
Definition ows_struct.h:180
buffer * type
Definition ows_struct.h:212
union Ows_request::@0 request
ows_version * version
Definition ows_struct.h:353
enum ows_service service
Definition ows_struct.h:355
wfs_request * wfs
Definition ows_struct.h:357
enum ows_method method
Definition ows_struct.h:354
ows_request * request
Definition ows_struct.h:403
ows_meta * metadata
Definition ows_struct.h:384
bool check_schema
Definition ows_struct.h:397
xmlSchemaPtr schema_wfs_110
Definition ows_struct.h:408
xmlSchemaPtr schema_wfs_100
Definition ows_struct.h:407
ows_layer_list * layers
Definition ows_struct.h:402

Generated for tinyows by doxygen 1.9.7