Shared connection
[handlerosm.git] / handler_server_info.c
blobe80f93d015790c3b18c60422803e3db991a0bca9
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* Cherokee
5 * Authors:
6 * Alvaro Lopez Ortega <alvaro@alobbs.com>
8 * Copyright (C) 2001-2008 Alvaro Lopez Ortega
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
25 #include "common-internal.h"
26 #include "handler_server_info.h"
28 #ifdef HAVE_SYS_UTSNAME_H
29 # include <sys/utsname.h>
30 #endif
32 #include "util.h"
33 #include "connection.h"
34 #include "connection-protected.h"
35 #include "server.h"
36 #include "server-protected.h"
37 #include "plugin_loader.h"
38 #include "connection_info.h"
40 #define CHANGES_TIME_DEFAULT 1
41 #define CHANGES_TIME_MAX 24
43 #define OSM_TAG "osm"
44 #define OSM_VERSION "0.5"
45 #define OSM_GENERATOR "Cherokee OSM API generator"
46 #define OSM_ATTRIBUTES "version=\"" OSM_VERSION "\" generator=\"" OSM_GENERATOR "\""
48 #define NODE_TAG "node"
49 #define NODE_ATTRIBUTES "id=\"%s\" lat=\"%s\" lon=\"%s\" visible=\"%s\" user=\"%s\" timestamp=\"%s\""
51 #define TAG_TAG "tag"
52 #define TAG_ATTRIBUTES "k=\"%s\" v=\"%s\""
54 #define WAY_TAG "way"
55 #define WAY_ATTRIBUTES "id=\"%s\" visible=\"%s\" user=\"%s\" timestamp=\"%s\""
57 #define ND_TAG "nd"
58 #define ND_ATTRIBUTES "ref=\"%s\""
60 #define RELATION_TAG "relation"
61 #define RELATION_ATTRIBUTES "id=\"%s\" visible=\"%s\" user=\"%s\" timestamp=\"%s\""
63 #define MEMBER_TAG "member"
64 #define MEMBER_ATTRIBUTES "type=\"%s\" ref=\"%s\" role=\"%s\""
66 #define XMLHEADER "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"CRLF
67 #define XML(THISTAG,LEVEL) LEVEL "<" THISTAG ## _TAG " " THISTAG ## _ATTRIBUTES
68 #define XMLCONTINUE ">" CRLF
69 #define XMLCLOSESHORT "/>" CRLF
70 #define XMLCLOSE(THISTAG,LEVEL) LEVEL "</" THISTAG ## _TAG ">" CRLF
72 #define PREFERENCES_TAG "preferences"
73 #define PREFERENCES_ATTRIBUTES ""
74 #define PREFERENCE_TAG "preference"
75 #define PREFERENCE_ATTRIBUTES "k=\"%s\" v=\"%s\""
77 #define SQL_NODE "SELECT id, X(g), Y(g), visible, 'not_implemented', '2007-09-07T16:39:10+01:00', name, value FROM nodes LEFT JOIN node_tags ON id = node"
78 #define SQL_NODE_BY_ID SQL_NODE " WHERE id = %ld"
79 #define SQL_NODE_BY_BBOX SQL_NODE " WHERE WithIn(g, 'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))') = TRUE ORDER BY id"
80 //#define BBOX_SQL "SELECT id, X(g), Y(g), visible, timestamp, name, value FROM nodes, node_tags WHERE Touches(g, 'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))') = TRUE AND nodes.id = node_tags.node"
83 /* Plug-in initialization
85 PLUGIN_INFO_HANDLER_EASIEST_INIT (server_info, http_get | http_put | http_post );
88 /* Methods implementation
90 static ret_t
91 props_free (cherokee_handler_server_info_props_t *props)
93 return cherokee_module_props_free_base (MODULE_PROPS(props));
97 ret_t
98 cherokee_handler_server_info_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
100 cherokee_list_t *i;
101 cherokee_handler_server_info_props_t *props;
103 UNUSED(srv);
105 if (*_props == NULL) {
106 CHEROKEE_NEW_STRUCT (n, handler_server_info_props);
108 cherokee_module_props_init_base (MODULE_PROPS(n),
109 MODULE_PROPS_FREE(props_free));
110 n->just_about = false;
111 n->connection_details = false;
113 *_props = MODULE_PROPS(n);
116 props = PROP_SRV_INFO(*_props);
118 cherokee_config_node_foreach (i, conf) {
119 cherokee_config_node_t *subconf = CONFIG_NODE(i);
121 if (equal_buf_str (&subconf->key, "just_about")) {
122 props->just_about = atoi(subconf->val.buf);
123 } else if (equal_buf_str (&subconf->key, "connection_details")) {
124 props->connection_details = atoi(subconf->val.buf);
125 } else {
126 PRINT_MSG ("ERROR: Handler file: Unknown key: '%s'\n", subconf->key.buf);
127 return ret_error;
131 return ret_ok;
134 static void
135 user_preferences(cherokee_buffer_t *buf)
137 cherokee_buffer_t content = CHEROKEE_BUF_INIT;
138 cherokee_buffer_add_str (buf, XML(PREFERENCES, " "));
139 if (content.len > 0) {
140 cherokee_buffer_add_str (buf, XMLCONTINUE);
141 cherokee_buffer_add_buffer (buf, &content);
142 cherokee_buffer_mrproper (&content);
143 cherokee_buffer_add_str (buf, XMLCLOSE(PREFERENCES, " "));
144 } else
145 cherokee_buffer_add_str (buf, XMLCLOSESHORT);
147 printf("%s\n", __func__);
150 static void
151 gpx_data(cherokee_buffer_t *buf, unsigned long int id)
153 printf("%s\n", __func__);
156 static void
157 gpx_details(cherokee_buffer_t *buf, unsigned long int id)
159 printf("%s\n", __func__);
162 static void
163 node_ways(cherokee_buffer_t *buf, unsigned long int id)
165 printf("%s\n", __func__);
168 enum OSM_State { OSM_FIND_FIRST = 0, OSM_GPX_ID, OSM_GPX_COMMAND, OSM_NODE_ID, OSM_NODE_COMMAND, OSM_NODES, OSM_NODES_PRE_PARSE, OSM_WAY_ID, OSM_WAY_COMMAND, OSM_WAYS_PRE_PARSE, OSM_WAYS_SEARCH, OSM_RELATION_ID, OSM_RELATION_COMMAND, OSM_RELATIONS_PRE_PARSE, OSM_RELATIONS_SEARCH, OSM_DONE}; // Move to .h later
170 static void
171 objtype_full(cherokee_buffer_t *buf, unsigned long int id, enum OSM_State state)
173 printf("%s\n", __func__);
176 static void
177 objtype_history(cherokee_buffer_t *buf, unsigned long int id, enum OSM_State state)
179 printf("%s\n", __func__);
182 static void
183 objtype_relations(cherokee_buffer_t *buf, unsigned long int id, enum OSM_State state)
185 printf("%s\n", __func__);
188 parse_changes(cherokee_avl_t *arguments, cherokee_buffer_t *buf) {
189 unsigned long int hours;
190 unsigned long int zoom;
191 void *param;
192 ret_t ret;
194 ret = cherokee_avl_get_ptr (arguments, "zoom", &param);
195 if (ret == ret_ok) {
196 zoom = strtoul(param, (char **) NULL, 10);
197 } else
198 zoom = 12;
200 ret = cherokee_avl_get_ptr (arguments, "start", &param);
201 if (ret == ret_ok) {
202 void *param2;
203 ret = cherokee_avl_get_ptr (arguments, "end", &param2);
204 if (ret == ret_ok) {
205 changes_bystartend(buf, zoom, (char *)param, (char *)param2);
207 } else {
208 ret = cherokee_avl_get_ptr (arguments, "hours", &param);
209 if (ret == ret_ok) {
210 hours = strtoul(param, (char **) NULL, 10);
211 } else
212 hours = 1;
214 changes_byhour(buf, zoom, hours);
218 changes_byhour(cherokee_buffer_t *buf, unsigned long int zoom, unsigned long int hours) {
219 cherokee_buffer_add_va (buf, "%d %d", zoom, hours);
222 changes_bystartend(cherokee_buffer_t *buf, unsigned long int zoom, char *start, char *end) {
223 cherokee_buffer_add_va (buf, "%d %s %s", zoom, start, end);
226 static ret_t fetch_bbox(cherokee_avl_t *arguments, double *left, double *bottom, double *right, double *top) {
227 void *param;
228 if (ret_ok == cherokee_avl_get_ptr (arguments, "bbox", &param)) {
229 char *token;
230 char *string = (char *) param;
231 if ((token = (char *) strsep( &string , ",")) != NULL) {
232 *left = strtod(token, (char **) NULL);
233 if (errno != ERANGE && (token = (char *) strsep( &string , ",")) != NULL) {
234 *bottom = strtod(token, (char **) NULL);
235 if (errno != ERANGE && (token = (char *) strsep( &string , ",")) != NULL) {
236 *right = strtod(token, (char **) NULL);
237 if (errno != ERANGE && (token = (char *) strsep( &string , ",")) != NULL) {
238 *top = strtod(token, (char **) NULL);
239 if (errno != ERANGE) {
240 return ret_ok;
247 return ret_error;
250 static void parse_nodes(cherokee_avl_t *arguments, cherokee_buffer_t *buf) {
252 static void parse_nodes_search(cherokee_avl_t *arguments, cherokee_buffer_t *buf) {
255 static void parse_relations(cherokee_avl_t *arguments, cherokee_buffer_t *buf) {
257 static void parse_relations_search(cherokee_avl_t *arguments, cherokee_buffer_t *buf) {
260 static void parse_ways(cherokee_avl_t *arguments, cherokee_buffer_t *buf) {
262 static void parse_ways_search(cherokee_avl_t *arguments, cherokee_buffer_t *buf) {
264 static void parse_trackpoints(cherokee_avl_t *arguments, cherokee_buffer_t *buf) {
265 double left, bottom, right, top;
266 unsigned long int page;
267 void *param;
268 printf("%s\n", __func__);
270 if (ret_ok == fetch_bbox(arguments, &left, &bottom, &right, &top)) {
271 cherokee_buffer_add_va (buf, "%f %f %f %f", left, bottom, right, top);
274 if (ret_ok == cherokee_avl_get_ptr (arguments, "page", &param)) {
275 page = strtoul(param, (char **) NULL, 10);
276 if (errno == ERANGE)
277 page = 1;
278 } else {
279 page = 1;
283 static void result_nodes_to_xml(MapiHdl *hdl, cherokee_buffer_t *buf) {
284 unsigned long int id = 0, id_old = 0;
285 unsigned short int state = 3;
286 while (mapi_fetch_row(*hdl)) {
287 char *name, *value;
288 id = strtoul(mapi_fetch_field(*hdl, 0), (char **) NULL, 10);
289 if (id_old != id) {
290 switch (state) {
291 case 0:
292 cherokee_buffer_add_str (buf, XMLCLOSESHORT);
293 break;
294 case 1:
295 cherokee_buffer_add_str (buf, XMLCLOSE(NODE, " "));
296 break;
298 cherokee_buffer_add_va (buf, XML(NODE, " "), mapi_fetch_field(*hdl, 0),
299 mapi_fetch_field(*hdl, 1),
300 mapi_fetch_field(*hdl, 2),
301 mapi_fetch_field(*hdl, 3),
302 mapi_fetch_field(*hdl, 4),
303 mapi_fetch_field(*hdl, 5) );
305 state = 0;
306 id_old = id;
308 name = mapi_fetch_field(*hdl, 6);
309 value = mapi_fetch_field(*hdl, 7);
311 if (name != NULL && value != NULL) {
312 if (state == 0)
313 cherokee_buffer_add_str (buf, XMLCONTINUE);
315 state = 1;
316 cherokee_buffer_add_va (buf, XML(TAG, " ") XMLCLOSESHORT, mapi_fetch_field(*hdl, 6), mapi_fetch_field(*hdl, 7) );
319 switch (state) {
320 case 0:
321 cherokee_buffer_add_str (buf, XMLCLOSESHORT);
322 break;
323 case 1:
324 cherokee_buffer_add_str (buf, XMLCLOSE(NODE, " "));
325 break;
329 static void get_node(cherokee_handler_server_info_t *hdl, unsigned long int id, cherokee_buffer_t *buf) {
330 MapiHdl mapi_hdl = NULL;
331 cherokee_buffer_t sql = CHEROKEE_BUF_INIT;
332 cherokee_buffer_add_va (&sql, SQL_NODE_BY_ID, id);
333 if ((mapi_hdl = mapi_query(hdl->dbh, sql.buf)) != NULL) {
334 result_nodes_to_xml(&mapi_hdl, buf);
335 mapi_cache_freeup(mapi_hdl, 100);
336 mapi_close_handle(mapi_hdl);
338 cherokee_buffer_mrproper(&sql);
341 static void parse_map(cherokee_handler_server_info_t *hdl, cherokee_buffer_t *buf) {
342 double left, bottom, right, top;
343 printf("%s\n", __func__);
344 cherokee_avl_t *arguments = HANDLER_CONN(hdl)->arguments;
346 if (ret_ok == fetch_bbox(arguments, &left, &bottom, &right, &top)) {
347 printf("%f %f %f %f\n", left, bottom, right, top);
348 cherokee_buffer_t sql = CHEROKEE_BUF_INIT;
349 MapiHdl mapi_hdl = NULL;
350 cherokee_buffer_add_va (&sql, SQL_NODE_BY_BBOX, bottom, left, bottom, right, top, right, top, left, bottom, left);
352 if ((mapi_hdl = mapi_query(hdl->dbh, sql.buf)) != NULL) {
353 result_nodes_to_xml(&mapi_hdl, buf);
354 mapi_cache_freeup(mapi_hdl, 100);
355 mapi_close_handle(mapi_hdl);
357 cherokee_buffer_mrproper(&sql);
362 static void
363 server_info_build_page (cherokee_handler_server_info_t *hdl)
365 ret_t ret;
366 cherokee_server_t *srv;
367 cherokee_connection_t *conn;
368 cherokee_buffer_t *buf;
369 cherokee_buffer_t content = CHEROKEE_BUF_INIT;
371 /* Init
373 buf = &hdl->buffer;
374 srv = HANDLER_SRV(hdl);
375 conn = HANDLER_CONN(hdl);
377 /* Parse the Request */
379 if (strlen(conn->request.buf) > 1) {
380 enum OSM_State state = OSM_FIND_FIRST;
381 unsigned long int id = 0;
382 char *string = conn->request.buf;
383 char *token;
384 void *param;
385 while (state != OSM_DONE && (token = (char *) strsep( &string , "/")) != NULL) {
386 if (*token == '\0')
387 continue;
389 switch (state) {
390 case OSM_FIND_FIRST:
391 switch (token[0]) {
392 case 'c':
393 /* GET /api/0.5/changes?hours=1&zoom=16&start=none&end=none */
394 parse_changes(conn->arguments, &content);
395 state = OSM_DONE;
396 break;
397 case 'n':
398 if (strlen(token) == 5 && token[4] == 's')
399 state = OSM_NODES_PRE_PARSE;
400 else
401 state = OSM_NODE_ID;
402 break;
403 case 'w':
404 if (strlen(token) == 4 && token[3] == 's')
405 state = OSM_WAYS_PRE_PARSE;
406 else
407 state = OSM_WAY_ID;
408 break;
409 case 'r':
410 if (strlen(token) == 9 && token[8] == 's')
411 state = OSM_RELATIONS_PRE_PARSE;
412 else
413 state = OSM_RELATION_ID;
414 break;
415 case 'g':
416 state = OSM_GPX_ID;
417 break;
418 case 'u':
419 user_preferences(&content);
420 break;
421 case 'm':
422 /* GET /api/0.5/map?bbox=LEFT,BOTTOM,RIGHT,TOP */
423 parse_map(hdl, &content);
424 break;
425 case 't':
426 /* GET /api/0.5/trackpoints?bbox=LEFT,BOTTOM,RIGHT,TOP&page=PAGENUMBER */
427 parse_trackpoints(conn->arguments, &content);
428 break;
429 case 's':
430 break;
432 break;
433 case OSM_GPX_ID:
434 case OSM_NODE_ID:
435 case OSM_WAY_ID:
436 case OSM_RELATION_ID:
437 id = strtoul(token, (char **) NULL, 10);
438 if (errno != ERANGE) state++;
439 get_node(hdl, id, &content);
440 break;
441 case OSM_GPX_COMMAND:
442 if (strlen(token) > 1) {
443 switch (token[1]) {
444 case 'a':
445 /* GET /api/0.5/gpx/<id>/data */
446 gpx_data(&content, id);
447 break;
448 case 'e':
449 /* GET /api/0.5/gpx/<id>/details */
450 gpx_details(&content, id);
451 break;
454 break;
456 /* GET /api/0.5/<objtype>/<id>/full
457 * GET /api/0.5/<objtype>/<id>/history
458 * GET /api/0.5/<objtype>/<id>/relations */
460 case OSM_NODE_COMMAND:
461 switch (token[0]) {
462 case 'w':
463 /* GET /api/0.5/node/<id>/ways */
464 node_ways(&content, id);
465 break;
467 case OSM_WAY_COMMAND:
468 case OSM_RELATION_COMMAND:
469 switch (token[0]) {
470 case 'f':
471 objtype_full(&content, id, state);
472 break;
473 case 'h':
474 objtype_history(&content, id, state);
475 break;
476 case 'r':
477 objtype_relations(&content, id, state);
478 break;
480 break;
481 case OSM_NODES_PRE_PARSE:
482 switch (token[0]) {
483 case '?':
484 /* GET /api/0.5/<objtype>s?<objtype>s=<id>[,<id>...] */
485 parse_nodes(conn->arguments, &content);
486 break;
487 case 's':
488 /* GET /api/0.5/nodes/search?type=<type>&value=<value> */
489 parse_nodes_search(conn->arguments, &content);
490 break;
492 break;
494 case OSM_RELATIONS_PRE_PARSE:
495 switch (token[0]) {
496 case '?':
497 /* GET /api/0.5/<objtype>s?<objtype>s=<id>[,<id>...] */
498 parse_relations(conn->arguments, &content);
499 break;
500 case 's':
501 /* GET /api/0.5/relations/search?type=<type>&value=<value> */
502 parse_relations_search(conn->arguments, &content);
503 break;
505 break;
507 case OSM_WAYS_PRE_PARSE:
508 switch (token[0]) {
509 case '?':
510 /* GET /api/0.5/<objtype>s?<objtype>s=<id>[,<id>...] */
511 parse_ways(conn->arguments, &content);
512 break;
513 case 's':
514 /* GET /api/0.5/ways/search?type=<type>&value=<value> */
515 parse_ways_search(conn->arguments, &content);
516 break;
518 break;
525 /* Add the page ending
527 // cherokee_buffer_mrproper (&table);
528 // cherokee_buffer_add_str (buf, PAGE_FOOT);
529 //cherokee_buffer_add(&content, conn->request.buf+1, conn->request.len-1);
531 cherokee_buffer_add_str (buf, XMLHEADER);
532 cherokee_buffer_add_str (buf, XML(OSM, ""));
533 if (content.len > 0) {
534 cherokee_buffer_add_str (buf, XMLCONTINUE);
535 cherokee_buffer_add_buffer (buf, &content);
536 cherokee_buffer_mrproper (&content);
537 cherokee_buffer_add_str (buf, XMLCLOSE(OSM, ""));
538 } else
539 cherokee_buffer_add_str (buf, XMLCLOSESHORT);
544 ret_t
545 cherokee_handler_server_info_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
547 ret_t ret;
548 CHEROKEE_NEW_STRUCT (n, handler_server_info);
550 /* Init the base class object
552 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(server_info));
554 MODULE(n)->init = (handler_func_init_t) cherokee_handler_server_info_init;
555 MODULE(n)->free = (module_func_free_t) cherokee_handler_server_info_free;
556 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_server_info_step;
557 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_server_info_add_headers;
559 HANDLER(n)->support = hsupport_length;
562 /* Init
564 ret = cherokee_buffer_init (&n->buffer);
565 if (unlikely(ret != ret_ok))
566 return ret;
568 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
569 if (unlikely(ret != ret_ok))
570 return ret;
572 n->dbh = mapi_connect("localhost", 50000, "monetdb", "monetdb", "sql", NULL);
574 *hdl = HANDLER(n);
575 return ret_ok;
579 ret_t
580 cherokee_handler_server_info_free (cherokee_handler_server_info_t *hdl)
582 cherokee_buffer_mrproper (&hdl->buffer);
583 mapi_destroy(hdl->dbh);
585 return ret_ok;
589 ret_t
590 cherokee_handler_server_info_init (cherokee_handler_server_info_t *hdl)
592 cherokee_connection_parse_args (HANDLER_CONN(hdl));
593 server_info_build_page (hdl);
595 return ret_ok;
599 ret_t
600 cherokee_handler_server_info_step (cherokee_handler_server_info_t *hdl, cherokee_buffer_t *buffer)
602 if (hdl->buffer.len > 0) {
603 cherokee_buffer_add_buffer (buffer, &hdl->buffer);
604 cherokee_buffer_move_to_begin (&hdl->buffer, buffer->size);
605 if (hdl->buffer.len == 0)
606 return ret_eof_have_data;
608 return ret_ok;
609 } else
610 return ret_eagain;
614 ret_t
615 cherokee_handler_server_info_add_headers (cherokee_handler_server_info_t *hdl, cherokee_buffer_t *buffer)
617 cherokee_buffer_add_str (buffer, "Content-Type: text/xml; charset=utf-8"CRLF);
618 // cherokee_buffer_add_str (buffer, "Content-Disposition: attachment; filename=\"map.osm\""CRLF);
619 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
620 return ret_ok;