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 #include <stdlib.h>
24 #include <stdio.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <time.h>
29
30 #include "../ows_define.h"
31 #include "ows.h"
32
33
34 /*
35 * Connect the ows to the database specified in configuration file
36 */
ows_pg(ows * o,char * con_str)37 static void ows_pg(ows * o, char *con_str)
38 {
39 assert(o);
40 assert(con_str);
41
42 o->pg = PQconnectdb(con_str);
43
44 if (PQstatus(o->pg) != CONNECTION_OK) {
45 ows_log(o, 1, PQerrorMessage(o->pg));
46 ows_error(o, OWS_ERROR_CONNECTION_FAILED, "Connection to database failed", "init_OWS");
47 return;
48 }
49
50 if (PQsetClientEncoding(o->pg, o->db_encoding->buf)) {
51 ows_log(o, 1, PQerrorMessage(o->pg));
52 ows_error(o, OWS_ERROR_CONNECTION_FAILED, "Wrong database encoding", "init_OWS");
53 return;
54 }
55
56 o->postgis_version = ows_psql_postgis_version(o);
57 if (!o->postgis_version)
58 ows_error(o, OWS_ERROR_CONNECTION_FAILED, "No PostGIS available in database", "init_OWS");
59 else if (ows_version_get(o->postgis_version) < 150)
60 ows_error(o, OWS_ERROR_CONNECTION_FAILED, "PostGIS version must be at least 1.5.0", "init_OWS");
61 }
62
63
64 /*
65 * Initialize an ows struct
66 */
ows_init()67 static ows *ows_init()
68 {
69 ows *o;
70
71 o = malloc(sizeof(ows));
72 assert(o);
73
74 o->init = true;
75 o->exit = false;
76 o->request = NULL;
77 o->cgi = NULL;
78 o->psql_requests = NULL;
79 o->pg = NULL;
80 o->pg_dsn = buffer_init();
81 o->output = stdout;
82 o->config_file = NULL;
83 o->mapfile = false;
84 o->online_resource = buffer_init();
85 o->schema_dir = buffer_init();
86 o->log_file = NULL;
87 o->log = NULL;
88 o->log_level=0;
89 o->encoding = buffer_init();
90 o->db_encoding = buffer_init();
91 o->layers = NULL;
92 o->max_features = 0;
93 o->degree_precision = 6;
94 o->meter_precision = 0;
95 o->max_geobbox = NULL;
96 o->display_bbox = true;
97 o->estimated_extent = false;
98 o->expose_pk = false;
99 o->check_schema = true;
100 o->check_valid_geom = true;
101 o->metadata = NULL;
102 o->contact = NULL;
103 o->postgis_version = NULL;
104 o->schema_wfs_100 = NULL;
105 o->schema_wfs_110 = NULL;
106 o->wfs_default_version = ows_version_init();
107 ows_version_set(o->wfs_default_version, 1, 1, 0);
108
109 return o;
110 }
111
112
113 /*
114 * Flush an ows structure
115 * Used for debug purpose
116 */
117 #ifdef OWS_DEBUG
ows_flush(ows * o,FILE * output)118 void ows_flush(ows * o, FILE * output)
119 {
120 assert(o);
121 assert(output);
122
123 fprintf(output, "exit : %d\n", o->exit?1:0);
124
125 if (o->config_file) fprintf(output, "config_file: %s\nmapfile %d\n", (char *) o->config_file->buf, o->mapfile?1:0);
126 if (o->schema_dir) fprintf(output, "schema_dir: %s\n", (char *) o->schema_dir->buf);
127 if (o->online_resource) fprintf(output, "online_resource: %s\n", (char *) o->online_resource->buf);
128 if (o->pg_dsn) fprintf(output, "pg: %s\n", (char *) o->pg_dsn->buf);
129 if (o->log_file) fprintf(output, "log file: %s\n", (char *) o->log_file->buf);
130 if (o->encoding) fprintf(output, "encoding: %s\n", (char *) o->encoding->buf);
131 if (o->db_encoding) fprintf(output, "db_encoding: %s\n", (char *) o->db_encoding->buf);
132
133 if (o->postgis_version) {
134 fprintf(output, "PostGIS version: %d.%d.%d\n", o->postgis_version->major,
135 o->postgis_version->minor,
136 o->postgis_version->release);
137 }
138
139 if (o->wfs_default_version) {
140 fprintf(output, "WFS default version: %d.%d.%d\n", o->wfs_default_version->major,
141 o->wfs_default_version->minor,
142 o->wfs_default_version->release);
143 }
144
145 if (o->metadata) {
146 fprintf(output, "metadata: ");
147 ows_metadata_flush(o->metadata, output);
148 fprintf(output, "\n");
149 }
150
151 if (o->contact) {
152 fprintf(output, "contact: ");
153 ows_contact_flush(o->contact, output);
154 fprintf(output, "\n");
155 }
156
157 if (o->cgi) {
158 fprintf(output, "cgi: ");
159 array_flush(o->cgi, output);
160 fprintf(output, "\n");
161 }
162
163 if (o->psql_requests) {
164 fprintf(output, "SQL requests: ");
165 list_flush(o->psql_requests, output);
166 fprintf(output, "\n");
167 }
168
169 if (o->layers) {
170 fprintf(output, "layers: ");
171 ows_layer_list_flush(o->layers, output);
172 fprintf(output, "\n");
173 }
174
175 if (o->request) {
176 fprintf(output, "request: ");
177 ows_request_flush(o->request, output);
178 fprintf(output, "\n");
179 }
180
181 fprintf(output, "max_features: %d\n", o->max_features);
182 fprintf(output, "degree_precision: %d\n", o->degree_precision);
183 fprintf(output, "meter_precision: %d\n", o->meter_precision);
184 fprintf(output, "expose_pk: %d\n", o->expose_pk?1:0);
185
186 if (o->max_geobbox) {
187 fprintf(output, "max_geobbox: ");
188 ows_geobbox_flush(o->max_geobbox, output);
189 fprintf(output, "\n");
190 }
191 fprintf(output, "display_bbox: %d\n", o->display_bbox?1:0);
192 fprintf(output, "estimated_extent: %d\n", o->estimated_extent?1:0);
193 fprintf(output, "check_schema: %d\n", o->check_schema?1:0);
194 fprintf(output, "check_valid_geom: %d\n", o->check_valid_geom?1:0);
195
196 fprintf(output, "schema WFS 1.0: %d\n", o->schema_wfs_100?1:0);
197 fprintf(output, "schema WFS 1.1: %d\n", o->schema_wfs_110?1:0);
198 }
199 #endif
200
201
202 /*
203 * Release ows struct
204 */
ows_free(ows * o)205 void ows_free(ows * o)
206 {
207 assert(o);
208
209 if (o->config_file) buffer_free(o->config_file);
210 if (o->schema_dir) buffer_free(o->schema_dir);
211 if (o->online_resource) buffer_free(o->online_resource);
212 if (o->pg) PQfinish(o->pg);
213 if (o->log_file) buffer_free(o->log_file);
214 if (o->log) fclose(o->log);
215 if (o->pg_dsn) buffer_free(o->pg_dsn);
216 if (o->cgi) array_free(o->cgi);
217 if (o->psql_requests) list_free(o->psql_requests);
218 if (o->layers) ows_layer_list_free(o->layers);
219 if (o->request) ows_request_free(o->request);
220 if (o->max_geobbox) ows_geobbox_free(o->max_geobbox);
221 if (o->metadata) ows_metadata_free(o->metadata);
222 if (o->contact) ows_contact_free(o->contact);
223 if (o->encoding) buffer_free(o->encoding);
224 if (o->db_encoding) buffer_free(o->db_encoding);
225 if (o->wfs_default_version) ows_version_free(o->wfs_default_version);
226 if (o->postgis_version) ows_version_free(o->postgis_version);
227 if (o->schema_wfs_100) xmlSchemaFree(o->schema_wfs_100);
228 if (o->schema_wfs_110) xmlSchemaFree(o->schema_wfs_110);
229
230 free(o);
231 o = NULL;
232 }
233
234
ows_log(ows * o,int log_level,const char * log)235 void ows_log(ows *o, int log_level, const char *log)
236 {
237 char *t, *p;
238 time_t ts;
239
240 if (o->log_file && !o->log) o->log = fopen(o->log_file->buf, "a");
241 if (!o->log || !(o->log_level & log_level)) return;
242
243 ts = time(NULL);
244 t = ctime(&ts);
245
246 /* Suppress ctime \n last char */
247 for (p = t; *p && *p != '\n'; p++);
248 *p = '\0';
249
250 if (log_level & 1) fprintf(o->log, "[%s] [ERROR] %s\n", t, log);
251 else if (log_level & 2) fprintf(o->log, "[%s] [EVENT] %s\n", t, log);
252 else if (log_level & 4) fprintf(o->log, "[%s] [QUERY] %s\n", t, log);
253 else if (log_level & 8) fprintf(o->log, "[%s] [SQL] %s\n", t, log);
254
255 fflush(o->log);
256 }
257
258
ows_usage(ows * o)259 void ows_usage(ows * o)
260 {
261 fprintf(stdout, "TinyOWS version: %s\n", TINYOWS_VERSION);
262 #ifdef TINYOWS_GIT_COMMIT
263 fprintf(stdout, "TinyOWS revision: %s\n", TINYOWS_GIT_COMMIT);
264 #endif
265 #if TINYOWS_FCGI
266 fprintf(stdout, "FCGI support: Yes\n");
267 #else
268 fprintf(stdout, "FCGI support: No\n");
269 #endif
270 if (o->mapfile)
271 fprintf(stdout, "Config File Path: %s (Mapfile)\n", o->config_file->buf);
272 else
273 fprintf(stdout, "Config File Path: %s (TinyOWS XML)\n", o->config_file->buf);
274
275 fprintf(stdout, "PostGIS Version: %d.%d.%d\n", o->postgis_version->major,
276 o->postgis_version->minor,
277 o->postgis_version->release);
278
279 fprintf(stdout, "PostGIS dsn: %s\n", o->pg_dsn->buf);
280 fprintf(stdout, "Output Encoding: %s\n", o->encoding->buf);
281 fprintf(stdout, "Database Encoding: %s\n", o->db_encoding->buf);
282 fprintf(stdout, "Schema dir: %s\n", o->schema_dir->buf);
283 if (o->log_file) {
284 fprintf(stdout, "Log file: %s\n", o->log_file->buf);
285 fprintf(stdout, "Log level: %s%s%s%s\n",(o->log_level & 1)?"ERROR ":"",
286 (o->log_level & 2)?"EVENT ":"",
287 (o->log_level & 4)?"QUERY ":"",
288 (o->log_level & 8)?"SQL":"" );
289 }
290
291 fprintf(stdout, "Display bbox: %s\n", o->display_bbox?"Yes":"No");
292 fprintf(stdout, "Estimated extent: %s\n", o->estimated_extent?"Yes":"No");
293 fprintf(stdout, "Check schema: %s\n", o->check_schema?"Yes":"No");
294 fprintf(stdout, "Check valid geoms: %s\n", o->check_valid_geom?"Yes":"No");
295 if (o->max_features)
296 fprintf(stdout, "Max features: %d\n", o->max_features);
297
298 fprintf(stdout, "Available layers:\n");
299 ows_layers_storage_flush(o, stdout);
300 }
301
302
ows_kvp_or_xml(ows * o,char * query)303 static void ows_kvp_or_xml(ows *o, char *query)
304 {
305 /*
306 * Request encoding and HTTP method WFS 1.1.0 -> 6.5
307 */
308
309 /* GET could only handle KVP */
310 if (cgi_method_get()) o->request->method = OWS_METHOD_KVP;
311
312 /* POST could handle KVP or XML encoding */
313 else if (cgi_method_post()) {
314 /* WFS 1.1.0 mandatory */
315 if ( !strcmp(getenv("CONTENT_TYPE"), "application/x-www-form-urlencoded")
316 || !strncmp(getenv("CONTENT_TYPE"), "application/x-www-form-urlencoded;", 34))
317 o->request->method = OWS_METHOD_KVP;
318 else if ( !strcmp(getenv("CONTENT_TYPE"), "text/xml")
319 || !strncmp(getenv("CONTENT_TYPE"), "text/xml;", 9)) /* Allowing charset */
320 o->request->method = OWS_METHOD_XML;
321
322 /* WFS 1.0.0 && CITE Test compliant */
323 else if ( !strcmp(getenv("CONTENT_TYPE"), "application/xml")
324 || !strcmp(getenv("CONTENT_TYPE"), "text/plain")
325 || !strncmp(getenv("CONTENT_TYPE"), "application/xml;", 16) /* Allowing charset */
326 || !strncmp(getenv("CONTENT_TYPE"), "text/plain;", 11)) /* Allowing charset */
327 o->request->method = OWS_METHOD_XML;
328
329 /* Command line Unit Test cases with XML values (not HTTP) */
330 } else if (!cgi_method_post() && !cgi_method_get() && query[0] == '<')
331 o->request->method = OWS_METHOD_XML;
332 else if (!cgi_method_post() && !cgi_method_get())
333 o->request->method = OWS_METHOD_KVP;
334
335 else ows_error(o, OWS_ERROR_REQUEST_HTTP, "Wrong HTTP request Method", "http");
336 }
337
338
main(int argc,char * argv[])339 int main(int argc, char *argv[])
340 {
341 ows *o;
342 char *query;
343
344 o = ows_init();
345 o->config_file = buffer_init();
346
347 /* Config Files */
348 if (getenv("TINYOWS_CONFIG_FILE"))
349 buffer_add_str(o->config_file, getenv("TINYOWS_CONFIG_FILE"));
350 else if (getenv("TINYOWS_MAPFILE")) {
351 buffer_add_str(o->config_file, getenv("TINYOWS_MAPFILE"));
352 o->mapfile = true;
353 } else
354 buffer_add_str(o->config_file, OWS_CONFIG_FILE_PATH);
355
356 LIBXML_TEST_VERSION
357 xmlInitParser();
358
359 /* Parse the configuration file and initialize ows struct */
360 if (!o->exit) ows_parse_config(o, o->config_file->buf);
361 if (!o->exit) ows_log(o, 2, "== TINYOWS STARTUP ==");
362
363 /* Connect the ows to the database */
364 if (!o->exit) ows_pg(o, o->pg_dsn->buf);
365 if (!o->exit) ows_log(o, 2, "== Connection PostGIS ==");
366
367 /* Fill layers storage metadata */
368 if (!o->exit) ows_layers_storage_fill(o);
369 if (!o->exit) ows_log(o, 2, "== Filling Storage ==");
370
371 o->init = false;
372
373 #if TINYOWS_FCGI
374 if (!o->exit) ows_log(o, 2, "== FCGI START ==");
375 while (FCGI_Accept() >= 0) {
376 #endif
377
378 query=NULL;
379 if (!o->exit) query = cgi_getback_query(o); /* Retrieve safely query string */
380 if (!o->exit) ows_log(o, 4, query); /* Log input query if asked */
381
382 if (!o->exit && (!query || !strlen(query))) {
383 /* Usage or Version command line options */
384 if (argc > 1) {
385 if ( !strncmp(argv[1], "--help", 6)
386 || !strncmp(argv[1], "-h", 2)
387 || !strncmp(argv[1], "--check", 7)) ows_usage(o);
388
389 else if ( !strncmp(argv[1], "--version", 9)
390 || !strncmp(argv[1], "-v", 2))
391 fprintf(stdout, "%s\n", TINYOWS_VERSION);
392
393 else ows_error(o, OWS_ERROR_INVALID_PARAMETER_VALUE, "Service Unknown", "service");
394
395 } else ows_error(o, OWS_ERROR_INVALID_PARAMETER_VALUE, "Service Unknown", "service");
396
397 o->exit=true; /* Have done what we have to */
398 }
399
400 if (!o->exit) o->request = ows_request_init();
401 if (!o->exit) ows_kvp_or_xml(o, query); /* Method is KVP or XML ? */
402
403 if (!o->exit) {
404
405 switch (o->request->method) {
406 case OWS_METHOD_KVP:
407 o->cgi = cgi_parse_kvp(o, query);
408 break;
409 case OWS_METHOD_XML:
410 o->cgi = cgi_parse_xml(o, query);
411 break;
412
413 default:
414 ows_error(o, OWS_ERROR_REQUEST_HTTP, "Wrong HTTP request Method", "http");
415 }
416 }
417
418 if (!o->exit) o->psql_requests = list_init();
419 if (!o->exit) ows_metadata_fill(o, o->cgi); /* Fill service's metadata */
420 if (!o->exit) ows_request_check(o, o->request, o->cgi, query); /* Process service request */
421
422 /* Run the right OWS service */
423 if (!o->exit) {
424 switch (o->request->service) {
425 case WFS:
426 o->request->request.wfs = wfs_request_init();
427 wfs_request_check(o, o->request->request.wfs, o->cgi);
428 if (!o->exit) wfs(o, o->request->request.wfs);
429 break;
430 default:
431 ows_error(o, OWS_ERROR_INVALID_PARAMETER_VALUE, "Service Unknown", "service");
432 }
433 }
434
435 if (o->request) {
436 ows_request_free(o->request);
437 o->request=NULL;
438 }
439
440 /* We allocated memory only on post case */
441 if (cgi_method_post() && query) free(query);
442
443 #if TINYOWS_FCGI
444 fflush(stdout);
445 o->exit = false;
446 }
447 ows_log(o, 2, "== FCGI SHUTDOWN ==");
448 OS_LibShutdown();
449 #endif
450 ows_log(o, 2, "== TINYOWS SHUTDOWN ==");
451 ows_free(o);
452
453 xmlCleanupParser();
454
455 return EXIT_SUCCESS;
456 }
457