1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
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
25 #include "common-internal.h"
26 #include "handler_server_info.h"
28 #ifdef HAVE_SYS_UTSNAME_H
29 # include <sys/utsname.h>
33 #include "connection.h"
34 #include "connection-protected.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
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\""
52 #define TAG_ATTRIBUTES "k=\"%s\" v=\"%s\""
55 #define WAY_ATTRIBUTES "id=\"%s\" visible=\"%s\" user=\"%s\" timestamp=\"%s\""
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
91 props_free (cherokee_handler_server_info_props_t
*props
)
93 return cherokee_module_props_free_base (MODULE_PROPS(props
));
98 cherokee_handler_server_info_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
101 cherokee_handler_server_info_props_t
*props
;
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
);
126 PRINT_MSG ("ERROR: Handler file: Unknown key: '%s'\n", subconf
->key
.buf
);
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
, " "));
145 cherokee_buffer_add_str (buf
, XMLCLOSESHORT
);
147 printf("%s\n", __func__
);
151 gpx_data(cherokee_buffer_t
*buf
, unsigned long int id
)
153 printf("%s\n", __func__
);
157 gpx_details(cherokee_buffer_t
*buf
, unsigned long int id
)
159 printf("%s\n", __func__
);
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
171 objtype_full(cherokee_buffer_t
*buf
, unsigned long int id
, enum OSM_State state
)
173 printf("%s\n", __func__
);
177 objtype_history(cherokee_buffer_t
*buf
, unsigned long int id
, enum OSM_State state
)
179 printf("%s\n", __func__
);
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
;
194 ret
= cherokee_avl_get_ptr (arguments
, "zoom", ¶m
);
196 zoom
= strtoul(param
, (char **) NULL
, 10);
200 ret
= cherokee_avl_get_ptr (arguments
, "start", ¶m
);
203 ret
= cherokee_avl_get_ptr (arguments
, "end", ¶m2
);
205 changes_bystartend(buf
, zoom
, (char *)param
, (char *)param2
);
208 ret
= cherokee_avl_get_ptr (arguments
, "hours", ¶m
);
210 hours
= strtoul(param
, (char **) NULL
, 10);
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
) {
228 if (ret_ok
== cherokee_avl_get_ptr (arguments
, "bbox", ¶m
)) {
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
) {
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
;
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", ¶m
)) {
275 page
= strtoul(param
, (char **) NULL
, 10);
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
)) {
288 id
= strtoul(mapi_fetch_field(*hdl
, 0), (char **) NULL
, 10);
292 cherokee_buffer_add_str (buf
, XMLCLOSESHORT
);
295 cherokee_buffer_add_str (buf
, XMLCLOSE(NODE
, " "));
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) );
308 name
= mapi_fetch_field(*hdl
, 6);
309 value
= mapi_fetch_field(*hdl
, 7);
311 if (name
!= NULL
&& value
!= NULL
) {
313 cherokee_buffer_add_str (buf
, XMLCONTINUE
);
316 cherokee_buffer_add_va (buf
, XML(TAG
, " ") XMLCLOSESHORT
, mapi_fetch_field(*hdl
, 6), mapi_fetch_field(*hdl
, 7) );
321 cherokee_buffer_add_str (buf
, XMLCLOSESHORT
);
324 cherokee_buffer_add_str (buf
, XMLCLOSE(NODE
, " "));
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
);
363 server_info_build_page (cherokee_handler_server_info_t
*hdl
)
366 cherokee_server_t
*srv
;
367 cherokee_connection_t
*conn
;
368 cherokee_buffer_t
*buf
;
369 cherokee_buffer_t content
= CHEROKEE_BUF_INIT
;
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
;
385 while (state
!= OSM_DONE
&& (token
= (char *) strsep( &string
, "/")) != NULL
) {
393 /* GET /api/0.5/changes?hours=1&zoom=16&start=none&end=none */
394 parse_changes(conn
->arguments
, &content
);
398 if (strlen(token
) == 5 && token
[4] == 's')
399 state
= OSM_NODES_PRE_PARSE
;
404 if (strlen(token
) == 4 && token
[3] == 's')
405 state
= OSM_WAYS_PRE_PARSE
;
410 if (strlen(token
) == 9 && token
[8] == 's')
411 state
= OSM_RELATIONS_PRE_PARSE
;
413 state
= OSM_RELATION_ID
;
419 user_preferences(&content
);
422 /* GET /api/0.5/map?bbox=LEFT,BOTTOM,RIGHT,TOP */
423 parse_map(hdl
, &content
);
426 /* GET /api/0.5/trackpoints?bbox=LEFT,BOTTOM,RIGHT,TOP&page=PAGENUMBER */
427 parse_trackpoints(conn
->arguments
, &content
);
436 case OSM_RELATION_ID
:
437 id
= strtoul(token
, (char **) NULL
, 10);
438 if (errno
!= ERANGE
) state
++;
439 get_node(hdl
, id
, &content
);
441 case OSM_GPX_COMMAND
:
442 if (strlen(token
) > 1) {
445 /* GET /api/0.5/gpx/<id>/data */
446 gpx_data(&content
, id
);
449 /* GET /api/0.5/gpx/<id>/details */
450 gpx_details(&content
, id
);
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
:
463 /* GET /api/0.5/node/<id>/ways */
464 node_ways(&content
, id
);
467 case OSM_WAY_COMMAND
:
468 case OSM_RELATION_COMMAND
:
471 objtype_full(&content
, id
, state
);
474 objtype_history(&content
, id
, state
);
477 objtype_relations(&content
, id
, state
);
481 case OSM_NODES_PRE_PARSE
:
484 /* GET /api/0.5/<objtype>s?<objtype>s=<id>[,<id>...] */
485 parse_nodes(conn
->arguments
, &content
);
488 /* GET /api/0.5/nodes/search?type=<type>&value=<value> */
489 parse_nodes_search(conn
->arguments
, &content
);
494 case OSM_RELATIONS_PRE_PARSE
:
497 /* GET /api/0.5/<objtype>s?<objtype>s=<id>[,<id>...] */
498 parse_relations(conn
->arguments
, &content
);
501 /* GET /api/0.5/relations/search?type=<type>&value=<value> */
502 parse_relations_search(conn
->arguments
, &content
);
507 case OSM_WAYS_PRE_PARSE
:
510 /* GET /api/0.5/<objtype>s?<objtype>s=<id>[,<id>...] */
511 parse_ways(conn
->arguments
, &content
);
514 /* GET /api/0.5/ways/search?type=<type>&value=<value> */
515 parse_ways_search(conn
->arguments
, &content
);
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
, ""));
539 cherokee_buffer_add_str (buf
, XMLCLOSESHORT
);
545 cherokee_handler_server_info_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
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
;
564 ret
= cherokee_buffer_init (&n
->buffer
);
565 if (unlikely(ret
!= ret_ok
))
568 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
569 if (unlikely(ret
!= ret_ok
))
572 n
->dbh
= mapi_connect("localhost", 50000, "monetdb", "monetdb", "sql", NULL
);
580 cherokee_handler_server_info_free (cherokee_handler_server_info_t
*hdl
)
582 cherokee_buffer_mrproper (&hdl
->buffer
);
583 mapi_destroy(hdl
->dbh
);
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
);
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
;
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
);