1 /******************************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: MapCache tile caching support file: WMS datasources
6 * Author: Thomas Bonfort and the MapServer team.
7 *
8 ******************************************************************************
9 * Copyright (c) 1996-2011 Regents of the University of Minnesota.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies of this Software or works derived from this Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 *****************************************************************************/
29
30
31 #include "mapcache.h"
32 #include "ezxml.h"
33 #include <apr_tables.h>
34 #include <apr_strings.h>
35
36 typedef struct mapcache_source_wms mapcache_source_wms;
37
38 /**\class mapcache_source_wms
39 * \brief WMS mapcache_source
40 * \implements mapcache_source
41 */
42 struct mapcache_source_wms {
43 mapcache_source source;
44 apr_table_t *wms_default_params; /**< default WMS parameters (SERVICE,REQUEST,STYLES,VERSION) */
45 apr_table_t *getmap_params; /**< WMS parameters specified in configuration */
46 apr_table_t *getfeatureinfo_params; /**< WMS parameters specified in configuration */
47 mapcache_http *http;
48 };
49
50 /**
51 * \private \memberof mapcache_source_wms
52 * \sa mapcache_source::render_map()
53 */
_mapcache_source_wms_render_map(mapcache_context * ctx,mapcache_source * psource,mapcache_map * map)54 void _mapcache_source_wms_render_map(mapcache_context *ctx, mapcache_source *psource, mapcache_map *map)
55 {
56 mapcache_source_wms *wms = (mapcache_source_wms*)psource;
57 mapcache_http *http;
58 apr_table_t *params = apr_table_clone(ctx->pool,wms->wms_default_params);
59
60 apr_table_setn(params,"BBOX",apr_psprintf(ctx->pool,"%f,%f,%f,%f",
61 map->extent.minx,map->extent.miny,map->extent.maxx,map->extent.maxy));
62 apr_table_setn(params,"WIDTH",apr_psprintf(ctx->pool,"%d",map->width));
63 apr_table_setn(params,"HEIGHT",apr_psprintf(ctx->pool,"%d",map->height));
64 apr_table_setn(params,"FORMAT","image/png");
65 apr_table_setn(params,"SRS",map->grid_link->grid->srs);
66
67 apr_table_overlap(params,wms->getmap_params,APR_OVERLAP_TABLES_SET);
68
69 if(map->dimensions && map->dimensions->nelts>0) {
70 int i;
71 for(i=0; i<map->dimensions->nelts; i++) {
72 mapcache_requested_dimension *rdim = APR_ARRAY_IDX(map->dimensions,i,mapcache_requested_dimension*);
73 /* set both DIM_key=val and key=val KVP params */
74 apr_table_setn(params,rdim->dimension->name,rdim->requested_value);
75 if(strcasecmp(rdim->dimension->name,"TIME") && strcasecmp(rdim->dimension->name,"ELEVATION")) {
76 char *dim_name = apr_pstrcat(ctx->pool,"DIM_",rdim->dimension->name,NULL);
77 apr_table_setn(params,dim_name,rdim->requested_value);
78 }
79 }
80 }
81
82 /* if the source has no LAYERS parameter defined, then use the tileset name
83 * as the LAYERS to request. When using mirror-mode, the source has no layers
84 * defined, it is added based on the incoming request
85 */
86 if(!apr_table_get(params,"layers")) {
87 apr_table_set(params,"LAYERS",map->tileset->name);
88 }
89
90 map->encoded_data = mapcache_buffer_create(30000,ctx->pool);
91 http = mapcache_http_clone(ctx, wms->http);
92 http->url = mapcache_http_build_url(ctx,http->url,params);
93 mapcache_http_do_request(ctx,http,map->encoded_data,NULL,NULL);
94 GC_CHECK_ERROR(ctx);
95
96 if(!mapcache_imageio_is_raw_tileset(map->tileset) && !mapcache_imageio_is_valid_format(ctx,map->encoded_data)) {
97 char *returned_data = apr_pstrndup(ctx->pool,(char*)map->encoded_data->buf,map->encoded_data->size);
98 ctx->set_error(ctx, 502, "wms request for tileset %s returned an unsupported format:\n%s",
99 map->tileset->name, returned_data);
100 }
101 }
102
_mapcache_source_wms_query(mapcache_context * ctx,mapcache_source * source,mapcache_feature_info * fi)103 void _mapcache_source_wms_query(mapcache_context *ctx, mapcache_source *source, mapcache_feature_info *fi)
104 {
105 mapcache_map *map = (mapcache_map*)fi;
106 mapcache_http *http;
107 mapcache_source_wms *wms = (mapcache_source_wms*)source;
108
109 apr_table_t *params = apr_table_clone(ctx->pool,wms->wms_default_params);
110 apr_table_overlap(params,wms->getmap_params,0);
111 apr_table_setn(params,"BBOX",apr_psprintf(ctx->pool,"%f,%f,%f,%f",
112 map->extent.minx,map->extent.miny,map->extent.maxx,map->extent.maxy));
113 apr_table_setn(params,"REQUEST","GetFeatureInfo");
114 apr_table_setn(params,"WIDTH",apr_psprintf(ctx->pool,"%d",map->width));
115 apr_table_setn(params,"HEIGHT",apr_psprintf(ctx->pool,"%d",map->height));
116 apr_table_setn(params,"SRS",map->grid_link->grid->srs);
117 apr_table_setn(params,"X",apr_psprintf(ctx->pool,"%d",fi->i));
118 apr_table_setn(params,"Y",apr_psprintf(ctx->pool,"%d",fi->j));
119 apr_table_setn(params,"INFO_FORMAT",fi->format);
120
121 apr_table_overlap(params,wms->getfeatureinfo_params,0);
122
123 if(map->dimensions && map->dimensions->nelts>0) {
124 int i;
125 for(i=0; i<map->dimensions->nelts; i++) {
126 mapcache_requested_dimension *rdim = APR_ARRAY_IDX(map->dimensions,i,mapcache_requested_dimension*);
127 /* set both DIM_key=val and key=val KVP params */
128 apr_table_setn(params,rdim->dimension->name,rdim->requested_value);
129 if(strcasecmp(rdim->dimension->name,"TIME") && strcasecmp(rdim->dimension->name,"ELEVATION")) {
130 char *dim_name = apr_pstrcat(ctx->pool,"DIM_",rdim->dimension->name,NULL);
131 apr_table_setn(params,dim_name,rdim->requested_value);
132 }
133 }
134 }
135
136 fi->data = mapcache_buffer_create(30000,ctx->pool);
137 http = mapcache_http_clone(ctx, wms->http);
138 http->url = mapcache_http_build_url(ctx,http->url,params);
139 mapcache_http_do_request(ctx,http,fi->data,NULL,NULL);
140 GC_CHECK_ERROR(ctx);
141
142 }
143
144 /**
145 * \private \memberof mapcache_source_wms
146 * \sa mapcache_source::configuration_parse()
147 */
_mapcache_source_wms_configuration_parse_xml(mapcache_context * ctx,ezxml_t node,mapcache_source * source,mapcache_cfg * config)148 void _mapcache_source_wms_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_source *source, mapcache_cfg *config)
149 {
150 ezxml_t cur_node;
151 mapcache_source_wms *src = (mapcache_source_wms*)source;
152
153
154 if ((cur_node = ezxml_child(node,"getmap")) != NULL) {
155 ezxml_t gm_node;
156 if ((gm_node = ezxml_child(cur_node,"params")) != NULL) {
157 for(gm_node = gm_node->child; gm_node; gm_node = gm_node->sibling) {
158 apr_table_set(src->getmap_params, gm_node->name, gm_node->txt);
159 }
160 } else {
161 ctx->set_error(ctx,400,"wms source %s <getmap> has no <params> block (should contain at least <LAYERS> child)",source->name);
162 return;
163 }
164 } else {
165 ctx->set_error(ctx,400,"wms source %s has no <getmap> block",source->name);
166 return;
167 }
168 if ((cur_node = ezxml_child(node,"getfeatureinfo")) != NULL) {
169 ezxml_t fi_node;
170 if ((fi_node = ezxml_child(cur_node,"info_formats")) != NULL) {
171 char *key,*last;
172 char *iformats;
173 source->info_formats = apr_array_make(ctx->pool,3,sizeof(char*));
174 iformats = apr_pstrdup(ctx->pool,fi_node->txt);
175
176 for (key = apr_strtok(iformats, "," , &last); key != NULL;
177 key = apr_strtok(NULL, ",", &last)) {
178 APR_ARRAY_PUSH(source->info_formats,char*) = key;
179 }
180 } else {
181 ctx->set_error(ctx,400,"wms source %s <getfeatureinfo> has no <info_formats> tag",source->name);
182 return;
183 }
184 if ((fi_node = ezxml_child(cur_node,"params")) != NULL) {
185 for(fi_node = fi_node->child; fi_node; fi_node = fi_node->sibling) {
186 apr_table_set(src->getfeatureinfo_params, fi_node->name, fi_node->txt);
187 }
188 } else {
189 ctx->set_error(ctx,400,"wms source %s <getfeatureinfo> has no <params> block (should contain at least <QUERY_LAYERS> child)",source->name);
190 return;
191 }
192 }
193 if ((cur_node = ezxml_child(node,"http")) != NULL) {
194 src->http = mapcache_http_configuration_parse_xml(ctx,cur_node);
195 }
196 }
197
198 /**
199 * \private \memberof mapcache_source_wms
200 * \sa mapcache_source::configuration_check()
201 */
_mapcache_source_wms_configuration_check(mapcache_context * ctx,mapcache_cfg * cfg,mapcache_source * source)202 void _mapcache_source_wms_configuration_check(mapcache_context *ctx, mapcache_cfg *cfg,
203 mapcache_source *source)
204 {
205 mapcache_source_wms *src = (mapcache_source_wms*)source;
206 /* check all required parameters are configured */
207 if(!src->http) {
208 ctx->set_error(ctx, 400, "wms source %s has no <http> request configured",source->name);
209 }
210 if(!apr_table_get(src->getmap_params,"LAYERS")) {
211 if(cfg->mode == MAPCACHE_MODE_NORMAL) {
212 ctx->set_error(ctx, 400, "wms source %s has no LAYERS", source->name);
213 }
214 }
215 if(source->info_formats) {
216 if(!apr_table_get(src->getfeatureinfo_params,"QUERY_LAYERS")) {
217 ctx->set_error(ctx, 400, "wms source %s has no QUERY_LAYERS", source->name);
218 }
219 }
220 }
221
mapcache_source_wms_create(mapcache_context * ctx)222 mapcache_source* mapcache_source_wms_create(mapcache_context *ctx)
223 {
224 mapcache_source_wms *source = apr_pcalloc(ctx->pool, sizeof(mapcache_source_wms));
225 if(!source) {
226 ctx->set_error(ctx, 500, "failed to allocate wms source");
227 return NULL;
228 }
229 mapcache_source_init(ctx, &(source->source));
230 source->source.type = MAPCACHE_SOURCE_WMS;
231 source->source._render_map = _mapcache_source_wms_render_map;
232 source->source.configuration_check = _mapcache_source_wms_configuration_check;
233 source->source.configuration_parse_xml = _mapcache_source_wms_configuration_parse_xml;
234 source->source._query_info = _mapcache_source_wms_query;
235 source->wms_default_params = apr_table_make(ctx->pool,4);;
236 source->getmap_params = apr_table_make(ctx->pool,4);
237 source->getfeatureinfo_params = apr_table_make(ctx->pool,4);
238 apr_table_add(source->wms_default_params,"VERSION","1.1.1");
239 apr_table_add(source->wms_default_params,"REQUEST","GetMap");
240 apr_table_add(source->wms_default_params,"SERVICE","WMS");
241 apr_table_add(source->wms_default_params,"STYLES","");
242 return (mapcache_source*)source;
243 }
244
245
246
247 /* vim: ts=2 sts=2 et sw=2
248 */
249