source: subversion/applications/utils/mod_mapnik_wms/mod_mapnik_wms.c @ 30525

Last change on this file since 30525 was 22430, checked in by frederik, 9 years ago

initial release of mod_mapnik_wms, an apache2 module for running a mapnik-based wms. documentation & mailing list announcement to follow in a few days

File size: 11.4 KB
Line 
1/**
2 * Mapnik WMS module for Apache
3 *
4 * This is the module code, in pure C. There's no functionality here,
5 * instead we just make calls into the C++ code from wms.cpp.
6 *
7 * part of the Mapnik WMS server module for Apache
8 */
9#define _GNU_SOURCE
10
11#include "apr.h"
12#include "apr_strings.h"
13#include "apr_thread_proc.h"
14#include "apr_optional.h"
15#include "apr_buckets.h"
16#include "apr_lib.h"
17#include "apr_poll.h"
18
19#define APR_WANT_STRFUNC
20#define APR_WANT_MEMFUNC
21#include "apr_want.h"
22
23#include "util_filter.h"
24#include "ap_config.h"
25#include "httpd.h"
26#include "http_config.h"
27#include "http_request.h"
28#include "http_core.h"
29#include "http_protocol.h"
30#include "http_main.h"
31#include "http_log.h"
32#include "util_script.h"
33#include "ap_mpm.h"
34#include "mod_core.h"
35#include "mod_cgi.h"
36#include "wms.h"
37
38module AP_MODULE_DECLARE_DATA mapnik_wms_module;
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <stdarg.h>
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <sys/socket.h>
47#include <sys/un.h>
48#include <unistd.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <limits.h>
52#include <time.h>
53#include <assert.h>
54
55pthread_mutex_t planet_lock = PTHREAD_MUTEX_INITIALIZER;
56
57static int wms_handler(request_rec *r)
58{
59    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "wms handler, h is %s", r->handler);
60   
61    if(strcmp(r->handler, "wms-handler"))
62        return DECLINED;
63
64    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "wms handler: %s", r->uri);
65
66    /* We set the content type before doing anything else */
67    ap_set_content_type(r, "text/html");
68    /* If the request is for a header only, and not a request for
69     * the whole content, then return OK now. We don't have to do
70     * anything else. */
71    if (r->header_only) 
72    {
73         return OK;
74    }
75
76    return wms_handle(r);
77}
78
79static void child_init(apr_pool_t *p, server_rec *s)
80{
81    // unused
82}
83
84static const char *handle_srs_option(cmd_parms *cmd, void *mconfig, const char *word)
85{
86    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
87    cfg->srs[cfg->srs_count++] = word;
88    return NULL;
89}
90static const char *handle_log_option(cmd_parms *cmd, void *mconfig, const char *word)
91{
92    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
93    cfg->logfile = word;
94    return NULL;
95}
96static const char *handle_datasource_option(cmd_parms *cmd, void *mconfig, const char *word)
97{
98    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
99    cfg->datasource[cfg->datasource_count++] = word;
100    return NULL;
101}
102static const char *handle_font_option(cmd_parms *cmd, void *mconfig, const char *word)
103{
104    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
105    cfg->font[cfg->font_count++] = word;
106    return NULL;
107}
108static const char *handle_map_option(cmd_parms *cmd, void *mconfig, const char *word)
109{
110    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
111    cfg->map = word;
112    return NULL;
113}
114static const char *handle_title_option(cmd_parms *cmd, void *mconfig, const char *word)
115{
116    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
117    cfg->title = word;
118    return NULL;
119}
120static const char *handle_top_layer_title_option(cmd_parms *cmd, void *mconfig, const char *word)
121{
122    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
123    cfg->top_layer_title = word;
124    return NULL;
125}
126static const char *handle_top_layer_name_option(cmd_parms *cmd, void *mconfig, const char *word)
127{
128    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
129    cfg->top_layer_name = word;
130    return NULL;
131}
132static const char *handle_sub_layer_option(cmd_parms *cmd, void *mconfig, int yesno)
133{
134    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
135    cfg->include_sub_layers = yesno;
136    return NULL;
137}
138static const char *handle_debug_option(cmd_parms *cmd, void *mconfig, int yesno)
139{
140    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
141    cfg->debug = yesno;
142    return NULL;
143}
144static const char *handle_url_option(cmd_parms *cmd, void *mconfig, const char *word)
145{
146    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
147    cfg->url = word;
148    return NULL;
149}
150#ifdef USE_KEY_DATABASE
151static const char *handle_keyfile_option(cmd_parms *cmd, void *mconfig, const char *word)
152{
153    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
154    cfg->key_db_file = word;
155    return NULL;
156}
157static const char *handle_mdw_option(cmd_parms *cmd, void *mconfig, const char *word)
158{
159    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
160    cfg->max_demo_width = atoi(word);
161    return NULL;
162}
163static const char *handle_mdh_option(cmd_parms *cmd, void *mconfig, const char *word)
164{
165    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
166    cfg->max_demo_height = atoi(word);
167    return NULL;
168}
169#endif
170static const char *handle_minlat_option(cmd_parms *cmd, void *mconfig, const char *word)
171{
172    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
173    cfg->miny = atof(word);
174    return NULL;
175}
176static const char *handle_minlon_option(cmd_parms *cmd, void *mconfig, const char *word)
177{
178    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
179    cfg->minx = atof(word);
180    return NULL;
181}
182static const char *handle_maxlat_option(cmd_parms *cmd, void *mconfig, const char *word)
183{
184    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
185    cfg->maxy = atof(word);
186    return NULL;
187}
188static const char *handle_maxlon_option(cmd_parms *cmd, void *mconfig, const char *word)
189{
190    struct wms_cfg *cfg = ap_get_module_config(cmd->server->module_config, &mapnik_wms_module);
191    cfg->maxx = atof(word);
192    return NULL;
193}
194static int wms_post_config(apr_pool_t *pconf, apr_pool_t *plog,
195   apr_pool_t *ptemp, server_rec *s)
196{
197   while(s)
198   {
199       struct wms_cfg *cfg = ap_get_module_config(s->module_config, &mapnik_wms_module);
200        if (!cfg->initialized)
201            wms_initialize(s, cfg, pconf);
202       s=s->next;
203    }
204    return OK;
205}
206
207static void register_hooks(__attribute__((unused)) apr_pool_t *p)
208{
209    ap_hook_child_init(child_init, NULL, NULL, APR_HOOK_MIDDLE);
210    ap_hook_post_config(wms_post_config, NULL, NULL, APR_HOOK_MIDDLE);
211    ap_hook_handler(wms_handler, NULL, NULL, APR_HOOK_MIDDLE);
212}
213
214static const command_rec wms_options[] =
215{
216    AP_INIT_ITERATE(
217        "WmsSrs",
218        handle_srs_option,
219        NULL,
220        RSRC_CONF,
221        "WmsSrs takes a list of allowed SRS names for its argument. They must be supported by the underlying Mapnik installation."
222    ),
223    AP_INIT_ITERATE(
224        "MapnikDatasources",
225        handle_datasource_option,
226        NULL,
227        RSRC_CONF,
228        "MapnikDatasources is the path to Mapnik data source modules."
229    ),
230    AP_INIT_ITERATE(
231        "MapnikFonts",
232        handle_font_option,
233        NULL,
234        RSRC_CONF,
235        "MapnikFonts takes a list of ttf files to make availalbe to Mapnik."
236    ),
237    AP_INIT_TAKE1(
238        "MapnikMap",
239        handle_map_option,
240        NULL,
241        RSRC_CONF,
242        "MapnikMap is the path to the map file."
243    ),
244    AP_INIT_TAKE1(
245        "WmsTitle",
246        handle_title_option,
247        NULL,
248        RSRC_CONF,
249        "WmsTitle is the title for your WMS server you want to return for GetCapability requests."
250    ),
251    AP_INIT_TAKE1(
252        "WmsTopLayerTitle",
253        handle_top_layer_title_option,
254        NULL,
255        RSRC_CONF,
256        "WmsTopLayerTitle is the title for the top-level layer."
257    ),
258    AP_INIT_TAKE1(
259        "WmsTopLayerName",
260        handle_top_layer_name_option,
261        NULL,
262        RSRC_CONF,
263        "WmsTopLayerName is the name for the top-level layer."
264    ),
265    AP_INIT_FLAG(
266        "WmsIncludeSubLayers",
267        handle_sub_layer_option,
268        NULL,
269        RSRC_CONF,
270        "When WmsIncludeSubLayers is given, Mapnik's sub layers will be exposed."
271    ),
272    AP_INIT_FLAG(
273        "WmsDebug",
274        handle_debug_option,
275        NULL,
276        RSRC_CONF,
277        "When WmsDebug is set, the map file will be loaded for each request instead of once at startup."
278    ),
279    AP_INIT_TAKE1(
280        "MapnikLog",
281        handle_log_option,
282        NULL,
283        RSRC_CONF,
284        "MapnikLog is the name of the log file to write Mapnik debug output to."
285    ),
286    AP_INIT_TAKE1(
287        "WmsUrl",
288        handle_url_option,
289        NULL,
290        RSRC_CONF,
291        "WmsUrl is the URL under which your WMS server can be reached from the outside. It is used in constructing the GetCapabilities response."
292    ),
293#ifdef USE_KEY_DATABASE
294    AP_INIT_TAKE1(
295        "WmsKeyDb",
296        handle_keyfile_option,
297        NULL,
298        RSRC_CONF,
299        "WmsKeyDb is the file name of the key data base. If unset, no key checking will be done."
300    ),
301    AP_INIT_TAKE1(
302        "WmsMaxDemoWidth",
303        handle_mdw_option,
304        NULL,
305        RSRC_CONF,
306        "WmsMaxDemoWidth is the maximum image width served for demo accounts."
307    ),
308    AP_INIT_TAKE1(
309        "WmsMaxDemoHeight",
310        handle_mdh_option,
311        NULL,
312        RSRC_CONF,
313        "WmsMaxDemoHeight is the maximum image height served for demo accounts."
314    ),
315#endif
316    AP_INIT_TAKE1(
317        "WmsExtentMinLon",
318        handle_minlon_option,
319        NULL,
320        RSRC_CONF,
321        "WmsExtentMinLon is the minimum longitude of data"
322    ),
323    AP_INIT_TAKE1(
324        "WmsExtentMaxLon",
325        handle_maxlon_option,
326        NULL,
327        RSRC_CONF,
328        "WmsExtentMaxLon is the maximum longitude of data"
329    ),
330    AP_INIT_TAKE1(
331        "WmsExtentMinLat",
332        handle_minlat_option,
333        NULL,
334        RSRC_CONF,
335        "WmsExtentMinLat is the minimum latitude of data"
336    ),
337    AP_INIT_TAKE1(
338        "WmsExtentMaxLat",
339        handle_maxlat_option,
340        NULL,
341        RSRC_CONF,
342        "WmsExtentMaxLat is the maximum latitude of data"
343    ),
344    {NULL}
345};
346
347static void *create_wms_conf(apr_pool_t *p, server_rec *s)
348{
349  struct wms_cfg *newcfg;
350
351  // Allocate memory from the provided pool.
352  newcfg = (struct wms_cfg *) apr_pcalloc(p, sizeof(struct wms_cfg));
353
354  newcfg->srs_count = 0;
355  newcfg->font_count = 0;
356  newcfg->datasource_count = 0;
357  newcfg->title = 0;
358  newcfg->url = 0;
359  newcfg->map = 0;
360  newcfg->initialized = 0;
361  newcfg->top_layer_name = "OpenStreetMap WMS";
362  newcfg->top_layer_title = "OpenStreetMap WMS";
363  newcfg->include_sub_layers = 0;
364  newcfg->key_db_file = 0;
365  newcfg->max_demo_width = 0;
366  newcfg->max_demo_height = 0;
367  newcfg->debug = 0;
368  newcfg->minx = -179.9999;
369  newcfg->maxx = 179.9999;
370  newcfg->miny = -89.9999;
371  newcfg->maxy = 89.9999;
372
373  // Return the created configuration struct.
374  return (void *) newcfg;
375}
376
377module AP_MODULE_DECLARE_DATA mapnik_wms_module =
378{
379    STANDARD20_MODULE_STUFF,
380    NULL,           /* dir config creater */
381    NULL,           /* dir merger --- default is to override */
382    create_wms_conf,/* server config */
383    NULL,           /* merge server config */
384    wms_options,    /* command apr_table_t */
385    register_hooks  /* register hooks */
386};
387
388struct wms_conf *get_wms_cfg(request_rec *r)
389{
390   return (struct wms_conf *) ap_get_module_config(r->server->module_config, &mapnik_wms_module);
391}
392
Note: See TracBrowser for help on using the repository browser.