• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geographika / mapserver / 17709373190

14 Sep 2025 09:32AM UTC coverage: 41.466% (+0.09%) from 41.375%
17709373190

push

github

geographika
Add index templates

62086 of 149729 relevant lines covered (41.47%)

25036.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.89
/src/mapserv-index.cpp
1
/**********************************************************************
2
 *
3
 * Project:  MapServer
4
 * Purpose:  MapServer Index Page Implementation
5
 * Author:   Seth Girvin and the MapServer team.
6
 *
7
 **********************************************************************
8
 * Copyright (c) 1996-2025 Regents of the University of Minnesota.
9
 *
10
 * Permission is hereby granted, free of charge, to any person obtaining a
11
 * copy of this software and associated documentation files (the "Software"),
12
 * to deal in the Software without restriction, including without limitation
13
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14
 * and/or sell copies of the Software, and to permit persons to whom the
15
 * Software is furnished to do so, subject to the following conditions:
16
 *
17
 * The above copyright notice and this permission notice shall be included in
18
 * all copies of this Software or works derived from this Software.
19
 *
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26
 ****************************************************************************/
27

28
#include "mapserver.h"
29
#include "mapogcapi.h"
30
#include "mapserv-index.h"
31
#include "maptemplate.h"
32
#include "mapows.h"
33

34
#include "cpl_conv.h"
35

36
#include "third-party/include_nlohmann_json.hpp"
37
#include "third-party/include_pantor_inja.hpp"
38

39
using namespace inja;
40
using json = nlohmann::json;
41

42
/*
43
** HTML Templates
44
*/
45
#define TEMPLATE_HTML_INDEX "landing.html"
46

47
static std::vector<json> processWMS(mapObj *map) {
1✔
48

49
  std::vector<json> serviceDescs; // List of JSON objects
50

51
  // Create the first JSON object
52
  json serviceDesc1;
53
  const char *title = msOWSLookupMetadata(&(map->web.metadata), "MO", "title");
1✔
54
  if (!title) {
1✔
55
    title = map->name;
1✔
56
  }
57

58
  std::string api_root = getApiRootUrl(map, "MO");
1✔
59

60
  serviceDesc1["title"] = title;
2✔
61
  serviceDesc1["type"] = "WMS";
2✔
62
  serviceDesc1["url"] = api_root;
1✔
63

64
  serviceDescs.push_back(serviceDesc1); // Add to the list
1✔
65

66
  json serviceDesc2;
67
  serviceDesc2["title"] = title;
2✔
68
  serviceDesc2["type"] = "WMS";
2✔
69
  serviceDesc1["url"] = api_root;
1✔
70

71
  serviceDescs.push_back(serviceDesc2); // Add to the list
1✔
72

73
  return serviceDescs; // Return the list of JSON objects
1✔
74
}
×
75

76
static json processMap(mapObj *map) {
1✔
77
  json mapJson;
78
  mapJson["name"] = map->name;
3✔
79
  mapJson["title"] = "title";
2✔
80
  // object getTitle(map)
81

82
  // service-meta intended for machine consumption
83
  //
84
  // Create the "service-desc" array
85
  mapJson["service-desc"] = json::array();
1✔
86

87
  // json serviceDesc;
88
  // serviceDesc["href"] =
89
  //     "https://demo.mapserver.org/cgi-bin/"
90
  //     "msautotest?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities";
91
  // serviceDesc["title"] = "World WMS service";
92
  // serviceDesc["type"] = "text/xml";
93

94
#ifdef USE_WMS_SVR
95

96
  // WMS services
97
  std::vector<json> wmsServiceDescs = processWMS(map);
1✔
98

99
  // Add each JSON object to the "service-desc" array
100
  for (const auto &serviceDesc : wmsServiceDescs) {
3✔
101
    mapJson["service-desc"].push_back(serviceDesc);
2✔
102
  }
103

104
#endif /* USE_WMS_SVR */
105

106
  // Append the nested object to the "service-desc" array
107
  // mapJson["service-desc"].push_back(serviceDesc);
108

109
  return mapJson;
1✔
110
}
1✔
111

112
static json getMapJsonFromConfig(configObj *config) {
1✔
113

114
  const char *key = NULL;
115
  json links =
116
      json::array(); // Create an empty JSON array to store nested objects
1✔
117

118
  while (true) {
119
    key = msNextKeyFromHashTable(&config->maps, key);
2✔
120
    if (!key) {
2✔
121
      break; // No more keys
122
    }
123

124
    const char *pszValue = msLookupHashTable(&config->maps, key);
1✔
125
    if (pszValue) {
1✔
126
      mapObj *map = msLoadMap(pszValue, nullptr, config);
1✔
127
      if (!map) {
1✔
128
        // return -1; // Handle error case
129
        // try paths relative to the CONFIG file
130
        // TODO - do we want this apart from to make it easier for testing?
131
        const char *val;
132
        if ((val = CPLGetConfigOption("MAPSERVER_CONFIG_FILE", NULL)) != NULL) {
×
133
          char szPath[MS_MAXPATHLEN];
134
          char *path = msGetPath(val);
×
135
          if (path) {
×
136
            msBuildPath(szPath, path, pszValue);
×
137
            free(path); // Ensure msGetPath and free are compatible
×
138
            map = msLoadMap(szPath, nullptr, config);
×
139
          }
140
        }
141
      }
142
      if (!map) {
×
143
        // log error output
144
      } else {
145
        // Append the new JSON object to the "links" array
146
        links.push_back(processMap(map));
1✔
147
        msFreeMap(map);
1✔
148
      }
149
    }
150
  }
151

152
  return links;
1✔
153
}
154

155
static std::string getEnvVar(const char *envVar) {
×
156
  const char *value = getenv(envVar);
×
157
  return value ? std::string(value) : std::string();
×
158
}
159

160
static int processIndexRequest(configObj *config, OGCAPIFormat format) {
1✔
161
  json response;
162
  std::map<std::string, std::string> extraHeaders;
163
  std::string path;
164
  char fullpath[MS_MAXPATHLEN];
165

166
  response = {{"title", "Index Page"},
167
              {"description", "List of Mapfiles"},
168
              {"linkset", getMapJsonFromConfig(config)}};
11✔
169

170
  if (format == OGCAPIFormat::JSON) {
1✔
171
    outputJson(response, OGCAPI_MIMETYPE_JSON, extraHeaders);
1✔
172
  } else if (format == OGCAPIFormat::GeoJSON) {
×
173
    outputJson(response, OGCAPI_MIMETYPE_GEOJSON, extraHeaders);
×
174
  } else if (format == OGCAPIFormat::OpenAPI_V3) {
×
175
    outputJson(response, OGCAPI_MIMETYPE_OPENAPI_V3, extraHeaders);
×
176
  } else if (format == OGCAPIFormat::HTML) {
×
177
    path = getTemplateDirectory(NULL, "html_template_directory",
×
178
                                "MS_INDEX_TEMPLATE_DIRECTORY");
×
179
    if (path.empty()) {
×
180
      outputError(OGCAPI_CONFIG_ERROR, "Template directory not set.");
×
181
      return MS_FAILURE;
×
182
    }
183
    msBuildPath(fullpath, NULL, path.c_str());
×
184

185
    json j;
186
    j["response"] = response;
×
187

188
    // std::string api_root = "http://" + std::string(getenv("SERVER_NAME")) +
189
    //                        ":" + std::string(getenv("SERVER_PORT")) +
190
    //                        std::string(getenv("SCRIPT_NAME")) +
191
    //                        std::string(getenv("PATH_INFO"));
192

193
    std::string serverName = getEnvVar("SERVER_NAME");
×
194
    std::string serverPort = getEnvVar("SERVER_PORT");
×
195
    std::string scriptName = getEnvVar("SCRIPT_NAME");
×
196
    std::string pathInfo = getEnvVar("PATH_INFO");
×
197

198
    std::string api_root =
199
        "http://" + serverName + ":" + serverPort + scriptName + pathInfo;
×
200

201
    // extend the JSON with a few things that we need for templating
202
    j["template"] = {{"path", json::array()},
×
203
                     {"params", json::object()},
×
204
                     {"api_root", api_root},
205
                     {"title", "MapServer Index Page"},
206
                     {"tags", json::object()}};
×
207

208
    outputTemplate(fullpath, TEMPLATE_HTML_INDEX, j, OGCAPI_MIMETYPE_HTML);
×
209
  }
210

211
  return MS_SUCCESS;
212
}
11✔
213

214
int msOGCAPIDispatchIndexRequest(mapservObj *mapserv, configObj *config) {
1✔
215
#ifdef USE_OGCAPI_SVR
216
  if (!mapserv || !config)
1✔
217
    return -1; // Handle null pointers
218

219
  cgiRequestObj *request = mapserv->request;
1✔
220
  OGCAPIFormat format;
221
  format = msGetOutputFormat(request);
1✔
222

223
  return processIndexRequest(config, format);
1✔
224

225
#else
226
  msSetError(MS_OGCAPIERR, "OGC API server support is not enabled.",
227
             "msOGCAPIDispatchIndexRequest()");
228
  return MS_FAILURE;
229
#endif
230
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc