├── .gitignore
├── .travis.yml
├── LICENCE
├── Makefile
├── README.md
├── WINDOWS-INSTALL.md
├── binding.gyp
├── doc
├── Doxyfile
└── README.md
├── docker
└── latest
│ └── Dockerfile
├── examples
├── hello-world.js
├── wms-server.js
└── wms-server.map
├── lib
└── mapserv.js
├── package.json
├── src
├── error.cpp
├── error.hpp
├── map.cpp
├── map.hpp
├── node-mapserv.cpp
├── node-mapservutil.c
└── node-mapservutil.h
├── test
├── include-error.map
├── invalid.map
├── mapserv-test.js
└── valid.map
└── tools
├── config.py
├── git-bisect-run.sh
└── install-deps.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | coverage/
3 | node_modules/
4 | doc/.made
5 | doc/html
6 | doc/latex
7 | npm-debug.log
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Configuration file for Travis-CI testing
2 | # Test using
3 |
4 | language: node_js
5 | node_js:
6 | - "0.10"
7 | - "0.12"
8 | - "0.13"
9 | env:
10 | - MAPSERVER_COMMIT=rel-6-2-0 # v6.2.0
11 | - MAPSERVER_COMMIT=rel-6-2-1 # v6.2.1
12 | - MAPSERVER_COMMIT=rel-6-4-0 # v6.4.0
13 | - MAPSERVER_COMMIT=rel-6-4-1 # v6.4.1
14 | - MAPSERVER_COMMIT= # repository HEAD
15 | matrix:
16 | fast_finish: true
17 | # allow unstable versions to fail
18 | allow_failures:
19 | - node_js: "0.12"
20 | - node_js: "0.13"
21 | - env: MAPSERVER_COMMIT=
22 | before_install:
23 | - sudo apt-get install libgif-dev # mapserver dependencies
24 | - sh ./tools/install-deps.sh /tmp $MAPSERVER_COMMIT # install the dependencies
25 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright (c) 2012, GeoData Institute (www.geodata.soton.ac.uk)
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * - Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | *
11 | * - Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | * POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ##
2 | # Node-mapserv development targets
3 | #
4 | # This Makefile contains the following primary targets intended to facilitate
5 | # Linux based development:
6 | #
7 | # - `make build`: create a Debug build of the module
8 | # - `make test`: run the tests
9 | # - `make cover`: perform the code coverage analysis
10 | # - `make valgrind`: run the test suite under valgrind
11 | # - `make doc`: create the doxygen documentation
12 | # - `make clean`: remove generated files
13 | #
14 |
15 | # The location of the mapserver build directory
16 | ifeq ($(strip $(npm_config_mapserv_build_dir)),)
17 | npm_config_mapserv_build_dir = $(shell npm config get mapserv:build_dir)
18 | endif
19 |
20 | # The location of the `vows` test command
21 | VOWS = ./node_modules/.bin/vows
22 |
23 | # The location of the `node-gyp` module builder. Try and get a globally
24 | # installed version, falling back to a local install.
25 | NODE_GYP = $(shell which node-gyp)
26 | ifeq ($(NODE_GYP),)
27 | NODE_GYP = ./node_modules/.bin/node-gyp
28 | endif
29 |
30 | # The location of the `istanbul` JS code coverage framework. Try and get a
31 | # globally installed version, falling back to a local install.
32 | ISTANBUL=$(shell which istanbul)
33 | ifeq ($(ISTANBUL),)
34 | ISTANBUL = ./node_modules/.bin/istanbul
35 | endif
36 |
37 | # Dependencies for the test target
38 | test_deps=build \
39 | ./test/*.js \
40 | ./test/*.map \
41 | lib/*.js \
42 | $(VOWS)
43 |
44 |
45 | # Build the module
46 | all: build
47 | build: build/Debug/bindings.node
48 | build/Debug/bindings.node: $(NODE_GYP) src/*.hpp src/*.cpp src/*.h src/*.c
49 | npm_config_mapserv_build_dir=$(npm_config_mapserv_build_dir) $(NODE_GYP) -v --debug configure build
50 |
51 | # Test the module
52 | test: $(test_deps)
53 | $(VOWS) --spec ./test/mapserv-test.js
54 |
55 | # Run the test suite under valgrind
56 | valgrind: $(test_deps) $(ISTANBUL)
57 | valgrind --leak-check=full --show-reachable=yes --track-origins=yes \
58 | node --nouse_idle_notification --expose-gc \
59 | $(VOWS) test/mapserv-test.js
60 |
61 | # Perform the code coverage
62 | cover: coverage/index.html
63 | coverage/index.html: coverage/node-mapserv.info
64 | genhtml --output-directory coverage coverage/node-mapserv.info
65 | @echo "\033[0;32mPoint your browser at \`coverage/index.html\`\033[m\017"
66 | coverage/node-mapserv.info: coverage/bindings.info
67 | lcov --test-name node-mapserv \
68 | --add-tracefile coverage/lcov.info \
69 | --add-tracefile coverage/bindings.info \
70 | --output-file coverage/node-mapserv.info
71 | coverage/bindings.info: coverage/addon.info
72 | lcov --extract coverage/addon.info '*node-mapserv/src/*' --output-file coverage/bindings.info
73 | coverage/addon.info: coverage/lcov.info
74 | lcov --capture --base-directory src/ --directory . --output-file coverage/addon.info
75 | # This generates the JS lcov info as well as gcov `*.gcda` files:
76 | coverage/lcov.info: $(test_deps) $(ISTANBUL)
77 | node --nouse_idle_notification --expose-gc \
78 | $(ISTANBUL) cover --report lcovonly \
79 | $(VOWS) -- test/mapserv-test.js
80 |
81 | # Install required node modules
82 | $(NODE_GYP):
83 | npm install node-gyp
84 |
85 | $(VOWS): package.json
86 | npm install vows
87 | @touch $(VOWS)
88 |
89 | $(ISTANBUL): package.json
90 | npm install istanbul
91 | @touch $(ISTANBUL)
92 |
93 | # Generate the Doxygen documentation
94 | doc: doc/.made
95 | doc/.made: doc/Doxyfile
96 | chdir ./doc/ && doxygen
97 | @echo "\033[0;32mPoint your browser at \`doc/html/index.html\`\033[m\017"
98 | @touch doc/.made
99 |
100 | # Clean up any generated files
101 | clean: $(NODE_GYP)
102 | $(NODE_GYP) clean
103 | rm -rf coverage \
104 | doc/html \
105 | doc/latex
106 |
107 | .PHONY: test
108 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Node Mapserv
2 |
3 | [](http://travis-ci.org/geo-data/node-mapserv)
4 |
5 | `node-mapserv` is a Node.js module which makes the functionality provided by
6 | the traditional Mapserver `mapserv` CGI program available to Node code.
7 |
8 | `node-mapserv` is best thought of as a wrapper around CGI `mapserv`: internally
9 | it uses a C++ binding to shave away the thin layer representing the binary
10 | `mapserv` CGI interface, replacing it with a javascript interface. All the
11 | underlying `mapserv` logic and code remain the same.
12 |
13 | `node-mapserv` is *not* MapScript for Node. Instead it provides a simple
14 | declarative API for rendering mapserver mapfiles with the following benefits:
15 |
16 | * All the considerable functionality of CGI `mapserv` are at your disposal:
17 | there's no need to reinvent the wheel (maybe just add a few spokes here and
18 | there!).
19 |
20 | * Support for declarative mapfile programming: most of what can be accomplished
21 | imperatively using mapscript can be done declaratively by custom generating
22 | new mapfiles and tweaking existing mapfiles (see
23 | [this post](http://sgillies.net/blog/315/stop-using-mapscript/) for a more
24 | detailed discussion).
25 |
26 | * Adherence to the Node non-blocking philosophy: operations involving I/O (such
27 | as parsing mapfiles and rendering maps) are performed asynchronously in child
28 | threads which keeps the main event loop snappy. Rough benchmarks suggest
29 | performance is comparable to fastcgi mapserv (using `examples/wms-server.js`
30 | with a modified mapfile).
31 |
32 | * Robustly tested: The module has a suite of tests that exercises the whole
33 | API. The tests provide 96% line coverage and 95% function coverage; excluded
34 | code generally handles hard to replicate edge cases (e.g. memory
35 | exhaustion). This suite has been run through Valgrind to check for memory
36 | leaks.
37 |
38 | ## Usage
39 |
40 | It is assumed that you are familiar with
41 | [using `mapserv`](http://mapserver.org/cgi/index.html) and
42 | [creating mapfiles](http://mapserver.org/mapfile/index.html).
43 |
44 | The API is simple and defines the following general pattern:
45 |
46 | 1. Instantiate an instance of the `Map` class from a mapfile on the filesystem
47 | (using `Map.FromFile`) or a mapfile string (using `Map.FromString`).
48 |
49 | 2. Render the mapfile as many times as required using `Map.mapserv`. This
50 | function emulates Mapserver CGI `mapserv` functionality and as such requires
51 | the creation of CGI environment variables to define the request parameters.
52 |
53 | The following example illustrates these steps:
54 |
55 | ```javascript
56 | var mapserv = require('../lib/mapserv'), // the Mapserv module
57 | fs = require('fs'), // for filesystem operations
58 |
59 | // A minimalist mapfile string
60 | mapfile = "MAP \
61 | NAME hello \
62 | STATUS ON \
63 | EXTENT 0 0 4000 3000 \
64 | SIZE 400 300 \
65 | IMAGECOLOR 200 255 255 \
66 | LAYER \
67 | NAME 'credits' \
68 | STATUS DEFAULT \
69 | TRANSFORM FALSE \
70 | TYPE ANNOTATION \
71 | FEATURE \
72 | POINTS \
73 | 200 150 \
74 | END \
75 | TEXT 'Hello world. Mapserver rocks.' \
76 | END \
77 | CLASS \
78 | LABEL \
79 | TYPE BITMAP \
80 | COLOR 0 0 0 \
81 | END \
82 | END \
83 | END \
84 | END";
85 |
86 | // Instantiate a Map object from the mapfile string. You could use
87 | // `mapserv.Map.FromFile` instead.
88 | mapserv.Map.FromString(mapfile, function handleMap(err, map) {
89 | if (err) throw err; // error loading the mapfile
90 |
91 | // a minimal CGI environment
92 | var env = {
93 | REQUEST_METHOD: 'GET',
94 | QUERY_STRING: 'mode=map&layer=credits'
95 | };
96 |
97 | map.mapserv(env, function handleMapResponse(err, mapResponse) {
98 | if (err) {
99 | throw err; // error generating the response
100 | }
101 |
102 | // If the response is an image, save it to a file, otherwise write it
103 | // to standard output.
104 | var contentType = mapResponse.headers['Content-Type'][0]; // get the content type from the headers
105 | if (contentType.substr(0, 5) === 'image') {
106 | var filename = 'output.' + contentType.substr(6); // get the file extension from the content type
107 | fs.writeFile(filename, mapResponse.data, function onWrite(err) {
108 | if (err) {
109 | throw err; // error writing to file
110 | }
111 | console.log('Mapserver response written to `%s`', filename);
112 | });
113 | } else {
114 | console.log(mapResponse.data.toString());
115 | }
116 | });
117 | });
118 | ```
119 |
120 | Editing the mapfile string and using it to instantiate new `Map` objects will
121 | of course allow you to produce different maps.
122 |
123 | The above example can be found in the package as `examples/hello-world.js`.
124 | `examples/wms-server.js` provides a more full featured example that marries
125 | `node-mapserv` with the stock Node `http` module to create a cascading WMS
126 | server. In addition it illustrates:
127 |
128 | * How to pass a 'body' string to `Map.mapserv` representing the HTTP body of a
129 | request (e.g. used in HTTP POST and PUT requests).
130 |
131 | * The use of the `mapserv.createCGIEnvironment` function used to generate a CGI
132 | environment from an `http.ServerRequest` object.
133 |
134 | Versioning information is also available. From the Node REPL:
135 |
136 | ```
137 | > var mapserv = require('mapserv');
138 | > mapserv.versions
139 | { node_mapserv: '0.1.3',
140 | mapserver: '6.3-dev',
141 | mapserver_numeric: 60300,
142 | mapserver_details: 'MapServer version 6.3-dev OUTPUT=PNG OUTPUT=JPEG SUPPORTS=PROJ SUPPORTS=AGG SUPPORTS=FREETYPE SUPPORTS=CAIRO SUPPORTS=ICONV SUPPORTS=FRIBIDI SUPPORTS=WMS_SERVER SUPPORTS=WFS_SERVER SUPPORTS=WCS_SERVER SUPPORTS=FASTCGI SUPPORTS=THREADS SUPPORTS=GEOS INPUT=JPEG INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE' }
143 | ```
144 |
145 | ### Errors
146 |
147 | Errors generated by Mapserver include a number of useful details. This
148 | information is exposed by the following properties which are present on all
149 | errors returned by the module and named `MapserverError` (i.e. all errors
150 | passed to a callback):
151 |
152 | - **`code`**: an integer representing the error category
153 | - **`category`**: a description of the error category
154 | - **`routine`**: the name of the Mapserver routine generating the error
155 | - **`isReported`**: a boolean flagging whether the error has been rendered in
156 | any Mapserver output
157 | - **`errorStack`**: an array containing the stack of any errors leading up to
158 | the current error, most recent error first. This property is not available
159 | in errors present in the stack itself.
160 |
161 | ## Requirements
162 |
163 | * Linux OS (although it should work on other Unices with minimal effort -
164 | patches welcome!). Although not currently supported, the module has been
165 | built successfully on Windows - see `WINDOWS-INSTALL.md` for more details.
166 |
167 | * Node.js 0.10 (Not yet working with 0.12)
168 |
169 | * Mapserver >= 6.2. If you are using `Map.FromString` ensure that you are using
170 | Mapserver >= 6.2.1 or alternatively you have applied
171 | [this patch](https://github.com/mapserver/mapserver/commit/e9e48941e9b02378de57a8ad6c6aa0d070816b06).
172 | Mapserver *must* be compiled with support for threads.
173 |
174 | ## Installation
175 |
176 | ### Using NPM
177 |
178 | The latest stable release of Node Mapcache is available via the Node
179 | Package Manager:
180 |
181 | * Ensure [Node.js](http://nodejs.org) and [Mapserver](http://www.mapserver.org)
182 | are available on your system. Mapserver will need to have been built from
183 | source with the source directory still available.
184 |
185 | * Point `node-mapserv` to the Mapserver source directory. It uses the build
186 | files to configure itself during installation. E.g.
187 |
188 | `npm config set mapserv:build_dir /tmp/mapserver-6.2`
189 |
190 | * Get and install `node-mapserv`:
191 |
192 | `npm install mapserv`
193 |
194 | * Optionally test that everything is working as expected (recommended):
195 |
196 | `npm test mapserv`
197 |
198 | ### Using Docker
199 |
200 | Assuming you have [Docker](http://www.docker.io/) available on your
201 | system, the following command will obtain a docker image with the
202 | latest Node Mapserv code from git built against the latest Mapserver
203 | git checkout:
204 |
205 | docker pull homme/node-mapserv:latest
206 |
207 | Note that the latest Mapserver git checkout is the latest **at the
208 | time the image was built**. If you want the absolute latest code of
209 | both Node Mapserv *and* Mapserver, build the docker image yourself
210 | locally along these lines:
211 |
212 | docker build -t homme/node-mapserv:latest https://raw.github.com/geo-data/node-mapserv/master/docker/latest/Dockerfile
213 |
214 | By default the image runs the Node Mapserv tests:
215 |
216 | docker run homme/node-mapserv:latest
217 |
218 | Running Node directly from the image allows you to `require()` and
219 | play around with Node Mapserv interactively:
220 |
221 | docker run -t -i homme/node-mapserv:latest /usr/bin/node
222 | > var mapserv = require('mapserv');
223 | undefined
224 | > mapserv.versions
225 | { node_mapserv: '0.1.4',
226 | mapserver: '6.5-dev',
227 | mapserver_numeric: 60500,
228 | mapserver_details: 'MapServer version 6.5-dev OUTPUT=PNG OUTPUT=JPEG OUTPUT=KML SUPPORTS=PROJ SUPPORTS=AGG SUPPORTS=FREETYPE SUPPORTS=CAIRO SUPPORTS=SVG_SYMBOLS SUPPORTS=SVGCAIRO SUPPORTS=ICONV SUPPORTS=XMP SUPPORTS=FRIBIDI SUPPORTS=WMS_SERVER SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER SUPPORTS=SOS_SERVER SUPPORTS=THREADS SUPPORTS=GEOS INPUT=JPEG INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE' }
229 |
230 | See the [Docker Index](https://index.docker.io/u/homme/node-mapserv/)
231 | for further information.
232 |
233 | ## Recommendations
234 |
235 | * Avoid using Mapserver features that are not thread safe: `node-mapserv` makes
236 | heavy use of threads and although this is safe for core mapserver operations,
237 | some extended features should be avoided. See the
238 | [Mapserver FAQ](http://mapserver.org/faq.html?highlight=threads#is-mapserver-thread-safe)
239 | and GitHub issues #4041 and #4044 for further details.
240 |
241 | * Become familiar with Mapserver
242 | [runtime substitution](http://mapserver.org/cgi/runsub.html): this allows you
243 | to alter portions of a mapfile based on data passed via a CGI request.
244 |
245 | * Use the
246 | [`PROCESSING "CLOSE_CONNECTION=DEFER"`](http://mapserver.org/mapfile/layer.html#index-49)
247 | directive in you mapfiles in order to cache data connections where possible:
248 | `Map` instances wrap persistent mapfile data structures and can therefore
249 | benefit from pooling persistent data connections in the same way as fastcgi
250 | mapserv.
251 |
252 | * Check out [`node-mapcache`](https://npmjs.org/package/mapcache): this can
253 | work well in combination with `node-mapserv` for generating tiled maps.
254 |
255 | ## Developing
256 |
257 | Fork the code on GitHub or clone it:
258 |
259 | git clone https://github.com/geo-data/node-mapserv.git
260 | cd node-mapserv
261 |
262 | Build the module in Debug mode using:
263 |
264 | make build
265 |
266 | By default this uses the Mapserver build directory previously specified using
267 | `npm config set mapserv:build_dir`; to override this do something along the
268 | following lines:
269 |
270 | make build npm_config_mapserv_build_dir=/tmp/mapserver-6.2
271 |
272 | You may want to ensure you're building in a clean source tree in which case:
273 |
274 | make clean
275 |
276 | Add tests for your changes to `test/mapserv-test.js` and run them:
277 |
278 | make test
279 |
280 | Perform code coverage analysis to ensure all code paths in your changes are
281 | tested (this requires [`lcov`](http://ltp.sourceforge.net/coverage/lcov.php) be
282 | installed):
283 |
284 | make cover
285 |
286 | Finally run the test suite through `valgrind` to ensure you haven't introduced
287 | any memory issues:
288 |
289 | make valgrind
290 |
291 | And issue your pull request or patch...
292 |
293 | ### Documentation
294 |
295 | Doxygen based documentation is available for the C++ bindings:
296 |
297 | make doc
298 |
299 | ## Bugs
300 |
301 | Please report bugs or issues using the
302 | [GitHub issue tracker](https://github.com/geo-data/node-mapserv).
303 |
304 | ## Licence
305 |
306 | [BSD 2-Clause](http://opensource.org/licenses/BSD-2-Clause).
307 |
308 | ## Contact
309 |
310 | Homme Zwaagstra
311 |
--------------------------------------------------------------------------------
/WINDOWS-INSTALL.md:
--------------------------------------------------------------------------------
1 | # Node Mapserv on Windows
2 |
3 | Although Windows is not currently an officially supported platform for Node
4 | Mapserv, the module has been successfully built on Windows. The related GitHub
5 | issues ([#7](https://github.com/geo-data/node-mapserv/issues/7) and
6 | [#14](https://github.com/geo-data/node-mapserv/issues/14)) provide further
7 | details on building with Windows.
8 |
9 | ## Installation
10 |
11 | It would be nice to simplify the Windows build process to enable a simple `npm
12 | install mapserv` (in a similar manner to the Linux build) but for now it is a
13 | manual process along the following lines:
14 |
15 | 1. Ensure you have an appropriate version of Node and `node-gyp` installed.
16 |
17 | 2. [Download](https://github.com/geo-data/node-mapserv/tags) and unpack Node
18 | Mapserv. Take note of where the `binding.gyp` file is.
19 |
20 | 3. Download the appropriate Mapserver SDK from the
21 | [GDAL and MapServer build SDK packages](http://www.gisinternals.com/sdk/)
22 | section (e.g. selecting `release-1600-dev`). Take note of where the
23 | `Makefile` is.
24 |
25 | 4. Unpack the SDK and edit `binding.gyp` to change the `ms_buildkit%` variable
26 | to point to SDK root path.
27 |
28 | 5. Download the MapServer source from the
29 | [GDAL and MapServer latest release versions](http://www.gisinternals.com/sdk/)
30 | section (e.g. selecting `release-1600-gdal-1-10-0-mapserver-6-2-1` and then
31 | `release-1600-gdal-1-10-0-mapserver-6-2-1-src.zip`).
32 |
33 | 6. Unpack the Mapserver source in the root of the SDK. Edit `binding.gyp` to
34 | change the `ms_root%` variable to point to the Mapserver source root path.
35 |
36 | 7. Adapt the SDK `Makefile` to also point to your Mapserver source root
37 | directory (Search for `MS_DIR`).
38 |
39 | 8. Build Mapserver: in a MSVS console go in the SDK directory and type `nmake
40 | ms`. Ensure the libraries listed in `binding.gyp` correspond to those just
41 | built and edit `binding.gyp` if this isn't the case.
42 |
43 | 9. Build Node Mapserv: from a console in the Node Mapserv root directory type
44 | `npm install .`
45 |
46 | Note again that Windows is not supported so you will have to work through
47 | issues yourself but feel free to discuss suggestions and improvements on
48 | GitHub.
49 |
--------------------------------------------------------------------------------
/binding.gyp:
--------------------------------------------------------------------------------
1 | {
2 | "targets": [
3 | {
4 | "target_name": "bindings",
5 | "sources": [
6 | "src/node-mapserv.cpp",
7 | "src/map.cpp",
8 | "src/error.cpp",
9 | "src/node-mapservutil.c"
10 | ],
11 | "include_dirs": [
12 | "
18 |
19 | # Ensure the package repository is up to date
20 | RUN apt-get update -y
21 |
22 | # Install basic dependencies
23 | RUN apt-get install -y software-properties-common python-software-properties python g++ make cmake wget git
24 |
25 | # Install the ubuntu gis and Node repositories
26 | RUN add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable
27 | RUN add-apt-repository -y ppa:chris-lea/node.js
28 | RUN apt-get update
29 |
30 | # Install Node.js
31 | RUN apt-get install -y nodejs
32 |
33 | # Install mapserver dependencies provided by Ubuntu repositories
34 | RUN apt-get install -y libxml2-dev \
35 | libxslt1-dev \
36 | libproj-dev \
37 | libfribidi-dev \
38 | libcairo2-dev \
39 | librsvg2-dev \
40 | libmysqlclient-dev \
41 | libpq-dev \
42 | libcurl4-gnutls-dev \
43 | libexempi-dev \
44 | libgdal-dev \
45 | libgeos-dev
46 |
47 | # Install libharfbuzz from source as it is not in a repository
48 | RUN apt-get install -y bzip2
49 | RUN cd /tmp && wget http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-0.9.19.tar.bz2 && \
50 | tar xjf harfbuzz-0.9.19.tar.bz2 && \
51 | cd harfbuzz-0.9.19 && \
52 | ./configure && \
53 | make && \
54 | make install && \
55 | ldconfig
56 |
57 | # Install Mapserver itself
58 | RUN git clone --depth=1 https://github.com/mapserver/mapserver/ /usr/local/src/mapserver
59 | RUN mkdir /usr/local/src/mapserver/build && \
60 | cd /usr/local/src/mapserver/build && \
61 | cmake ../ -DWITH_THREAD_SAFETY=1 \
62 | -DWITH_PROJ=1 \
63 | -DWITH_KML=1 \
64 | -DWITH_SOS=1 \
65 | -DWITH_WMS=1 \
66 | -DWITH_FRIBIDI=1 \
67 | -DWITH_HARFBUZZ=1 \
68 | -DWITH_ICONV=1 \
69 | -DWITH_CAIRO=1 \
70 | -DWITH_RSVG=1 \
71 | -DWITH_MYSQL=1 \
72 | -DWITH_GEOS=1 \
73 | -DWITH_POSTGIS=1 \
74 | -DWITH_GDAL=1 \
75 | -DWITH_OGR=1 \
76 | -DWITH_CURL=1 \
77 | -DWITH_CLIENT_WMS=1 \
78 | -DWITH_CLIENT_WFS=1 \
79 | -DWITH_WFS=1 \
80 | -DWITH_WCS=1 \
81 | -DWITH_LIBXML2=1 \
82 | -DWITH_GIF=1 \
83 | -DWITH_EXEMPI=1 \
84 | -DWITH_XMLMAPFILE=1 \
85 | -DWITH_FCGI=0 && \
86 | make && \
87 | make install && \
88 | ldconfig
89 |
90 | # Install Node Mapserv. This installs to `/node_modules` so will always be found
91 | RUN git clone https://github.com/geo-data/node-mapserv/ /usr/local/src/node-mapserv
92 | RUN npm config set mapserv:build_dir /usr/local/src/mapserver/build && \
93 | npm install /usr/local/src/node-mapserv
94 | RUN npm install vows # so that the default command works
95 |
96 | # Run the Node Mapserv tests by default
97 | CMD npm test mapserv
98 |
--------------------------------------------------------------------------------
/examples/hello-world.js:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright (c) 2012, GeoData Institute (www.geodata.soton.ac.uk)
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * - Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | *
11 | * - Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | * POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | /**
29 | * A basic introduction to Node Mapserv
30 | *
31 | * This illustrates the core API and general usage pattern provided by the
32 | * Mapserv module by generating a map response and saving it to a file. It
33 | * shows how to:
34 | *
35 | * - instantiate a `Map` object from a mapfile string
36 | * - set up a minimal CGI environment for specifying map requests
37 | * - generate a map response using the `Map.mapserv` method
38 | * - access the `headers` and `data` properties in the map response
39 | */
40 |
41 | var mapserv = require('../lib/mapserv'), // the Mapserv module
42 | fs = require('fs'), // for filesystem operations
43 |
44 | // A minimalist mapfile string
45 | mapfile = "MAP \
46 | NAME hello \
47 | STATUS ON \
48 | EXTENT 0 0 4000 3000 \
49 | SIZE 400 300 \
50 | IMAGECOLOR 200 255 255 \
51 | LAYER \
52 | NAME 'credits' \
53 | STATUS DEFAULT \
54 | TRANSFORM FALSE \
55 | TYPE ANNOTATION \
56 | FEATURE \
57 | POINTS \
58 | 200 150 \
59 | END \
60 | TEXT 'Hello world. Mapserver rocks.' \
61 | END \
62 | CLASS \
63 | LABEL \
64 | TYPE BITMAP \
65 | COLOR 0 0 0 \
66 | END \
67 | END \
68 | END \
69 | END";
70 |
71 | // Instantiate a Map object from the mapfile string. You could use
72 | // `mapserv.Map.FromFile` instead.
73 | mapserv.Map.FromString(mapfile, function handleMap(err, map) {
74 | if (err) throw err; // error loading the mapfile
75 |
76 | // a minimal CGI environment
77 | var env = {
78 | REQUEST_METHOD: 'GET',
79 | QUERY_STRING: 'mode=map&layer=credits'
80 | };
81 |
82 | map.mapserv(env, function handleMapResponse(err, mapResponse) {
83 | if (err) {
84 | throw err; // error generating the response
85 | }
86 |
87 | // If the response is an image, save it to a file, otherwise write it
88 | // to standard output.
89 | var contentType = mapResponse.headers['Content-Type'][0]; // get the content type from the headers
90 | if (contentType.substr(0, 5) === 'image') {
91 | var filename = 'output.' + contentType.substr(6); // get the file extension from the content type
92 | fs.writeFile(filename, mapResponse.data, function onWrite(err) {
93 | if (err) {
94 | throw err; // error writing to file
95 | }
96 | console.log('Mapserver response written to `%s`', filename);
97 | });
98 | } else {
99 | console.log(mapResponse.data.toString());
100 | }
101 | });
102 | });
103 |
--------------------------------------------------------------------------------
/examples/wms-server.js:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright (c) 2012, GeoData Institute (www.geodata.soton.ac.uk)
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * - Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | *
11 | * - Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | * POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | /**
29 | * Set up Mapserv as a WMS server
30 | *
31 | * This provides an example of how to use the Mapserv module in combination
32 | * with the Node HTTP module to create a Cascading WMS server. The resulting
33 | * WMS server acts as a proxy to the Marine Geo WMS service. It can be
34 | * accessed using a standard WMS client or by using the built in mapserver
35 | * OpenLayers client.
36 | */
37 |
38 | var path = require('path'), // for file path manipulations
39 | http = require('http'), // for the http server
40 | mapserv = require('../lib/mapserv'), // the Mapserv module
41 | host = 'localhost', // the server name
42 | port = 3000, // which port will the server run on?
43 | baseUrl = "http://" + host + ":" + port, // what is the server url?
44 | mapfile = path.join(__dirname, 'wms-server.map'); // the location of the mapfile
45 |
46 | // Instantiate a Map object from the mapfile
47 | mapserv.Map.FromFile(mapfile, function handleMap(err, map) {
48 | if (err) throw err; // error loading the mapfile
49 |
50 | // fire up a http server, handling all requests
51 | http.createServer(function handleMapRequest(req, res) {
52 | var env = mapserv.createCGIEnvironment(req),
53 | buffer; // a `Buffer` object for the request body
54 |
55 | // buffer any request body
56 | req.once('data', function onFirstData(chunk) {
57 | buffer = chunk; // the initial chunk
58 |
59 | // deal with the rest of the message body
60 | req.on('data', function onData(chunk) {
61 | buffer.concat([chunk], 1);
62 | });
63 | });
64 |
65 | // no more request data: prepare our response
66 | req.on('end', function onEnd() {
67 | // delegate the request to the Map object, handling the response
68 | map.mapserv(env, buffer, function handleMapResponse(err, mapResponse) {
69 | console.log('Serving ' + req.url);
70 |
71 | if (err) {
72 | // the map returned an error: handle it
73 | if (mapResponse.data) {
74 | // return the error as rendered by mapserver
75 | res.writeHead(500, mapResponse.headers);
76 | res.end(mapResponse.data);
77 | } else {
78 | // A raw error we need to output ourselves
79 | res.writeHead(500, {'Content-Type': 'text/plain'});
80 | res.end(err.stack);
81 | }
82 | console.error(err.stack); // log the error
83 | return;
84 | }
85 |
86 | // send the map response to the client
87 | res.writeHead(200, mapResponse.headers);
88 | if (req.method !== 'HEAD') {
89 | res.end(mapResponse.data);
90 | } else {
91 | res.end();
92 | }
93 | });
94 | });
95 | }).listen(port, "localhost");
96 |
97 | console.log(
98 | "Cascading WMS Server running at " + baseUrl + " - try the following URL:\n" +
99 | baseUrl + "/?mode=browse&template=openlayers&layer=GMRT\n" +
100 | "or point a WMS client at " + baseUrl + "/?"
101 | );
102 | });
103 |
--------------------------------------------------------------------------------
/examples/wms-server.map:
--------------------------------------------------------------------------------
1 | # Used in the `node-mapserv` wms example
2 | MAP
3 | NAME "WMS-TEST"
4 | # Map image size
5 | SIZE 400 400
6 | UNITS dd
7 | EXTENT -180 -90 180 90
8 |
9 | PROJECTION
10 | 'init=epsg:4326'
11 | END
12 |
13 | IMAGECOLOR 255 255 255
14 | IMAGEQUALITY 95
15 | IMAGETYPE png
16 |
17 | OUTPUTFORMAT
18 | NAME png
19 | DRIVER 'GD/PNG'
20 | MIMETYPE 'image/png'
21 | IMAGEMODE RGBA
22 | EXTENSION 'png'
23 | END
24 |
25 | WEB
26 | # WMS server settings
27 | METADATA
28 | 'ows_title' 'WMS-TEST'
29 | 'ows_onlineresource' 'http://localhost:3000/'
30 | 'ows_srs' 'EPSG:4326'
31 | 'ows_enable_request' '*'
32 | END
33 | END
34 |
35 | LAYER
36 | NAME "GMRT"
37 | TYPE RASTER
38 | STATUS ON
39 | CONNECTION "http://gmrt.marine-geo.org/cgi-bin/mapserv?map=/public/mgg/web/gmrt.marine-geo.org/htdocs/services/map/wms_merc.map&"
40 | CONNECTIONTYPE WMS
41 | METADATA
42 | "ows_srs" "EPSG:4326"
43 | "ows_name" "GMRT"
44 | "ows_server_version" "1.0.0"
45 | "ows_format" "image/png"
46 | END
47 | END
48 | END
49 |
--------------------------------------------------------------------------------
/lib/mapserv.js:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright (c) 2012, GeoData Institute (www.geodata.soton.ac.uk)
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * - Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | *
11 | * - Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | * POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | /**
29 | * Mapserv module
30 | *
31 | * This acts as a JavaScript shim exposing the API defined in the C++ addon.
32 | *
33 | * See the README for further details on the module.
34 | */
35 |
36 | var bindings,
37 | path = require('path'), // for file path manipulations
38 | url = require('url'); // for url parsing
39 |
40 | // try and load the bindings
41 | try {
42 | bindings = require('../build/Release/bindings');
43 | } catch (err) {
44 | // perhaps it's a debug build...
45 | try {
46 | bindings = require('../build/Debug/bindings');
47 | } catch(err2) {
48 | // ... no it isn't; throw the original error
49 | throw err;
50 | }
51 | }
52 |
53 | /**
54 | * Create a CGI environment from a Node HTTP request object
55 | *
56 | * This is a utility function that facilitates the generation of CGI
57 | * environment variables from a Node HTTP request object.
58 | *
59 | * See
60 | *
61 | * for details of CGI environment variables.
62 | */
63 | function createCGIEnvironment(req, vars) {
64 | var urlParts = url.parse(decodeURIComponent(req.url)), // parse the request url
65 | host = req.headers.host.split(':'),
66 | env = {
67 | // Server specific variables:
68 | SERVER_SOFTWARE: 'Node.js',
69 | SERVER_NAME: host[0],
70 | GATEWAY_INTERFACE: 'CGI/1.1',
71 |
72 | // Request specific variables:
73 | SERVER_PROTOCOL: 'HTTP/' + req.httpVersion,
74 | SERVER_PORT: host[1],
75 | REQUEST_METHOD: req.method,
76 | PATH_INFO: urlParts.pathname || '/',
77 | PATH_TRANSLATED: path.resolve(path.join('.', urlParts.pathname)),
78 | SCRIPT_NAME: '/',
79 | QUERY_STRING: urlParts.query || '',
80 | REMOTE_ADDR: req.connection.remoteAddress
81 | },
82 | key;
83 |
84 | // add content and authorisation specific variables
85 | if ('content-length' in req.headers) {
86 | env.CONTENT_LENGTH = req.headers['content-length'];
87 | }
88 | if ('content-type' in req.headers) {
89 | env.CONTENT_TYPE = req.headers['content-type'];
90 | }
91 | if ('authorization' in req.headers) {
92 | var auth = req.headers.authorization.split(' ');
93 | env.AUTH_TYPE = auth[0];
94 | }
95 |
96 | // add client specific variables
97 | for (key in req.headers) {
98 | switch (key) {
99 | case 'host':
100 | case 'content-length':
101 | case 'content-type':
102 | case 'authorization':
103 | // skip already handled headers
104 | break;
105 | default:
106 | // convert the header to a CGI variable
107 | var name = 'HTTP_' + key.toUpperCase().replace(/-/g, '_');
108 | env[name] = req.headers[key];
109 | }
110 | }
111 |
112 | // add user specified variables
113 | if (vars) {
114 | for (key in vars) {
115 | env[key] = vars[key];
116 | }
117 | }
118 |
119 | return env;
120 | }
121 |
122 | module.exports.Map = bindings.Map;
123 | module.exports.versions = bindings.versions;
124 | module.exports.createCGIEnvironment = createCGIEnvironment;
125 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "config": {
3 | "include_dir": "",
4 | "lib_dir": ""
5 | },
6 | "author": "Homme Zwaagstra ",
7 | "name": "mapserv",
8 | "description": "All the functionality of Mapserver's mapserv CGI program made available to Node",
9 | "version": "0.1.5",
10 | "repository": {
11 | "type": "git",
12 | "url": "http://github.com/geo-data/node-mapserv.git"
13 | },
14 | "main": "lib/mapserv.js",
15 | "engines": {
16 | "node": ">=0.10 <0.11"
17 | },
18 | "scripts": {
19 | "test": "vows --spec ./test/mapserv-test.js"
20 | },
21 | "dependencies": {},
22 | "devDependencies": {
23 | "vows": "*",
24 | "istanbul": "*"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/error.cpp:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright (c) 2013, GeoData Institute (www.geodata.soton.ac.uk)
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * - Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | *
11 | * - Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | * POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | /**
29 | * @file error.cpp
30 | * @brief This defines the `MapserverError` class.
31 | */
32 |
33 | #include "error.hpp"
34 |
35 | Persistent MapserverError::MapserverError_symbol;
36 |
37 | /**
38 | * @defgroup error_properties Properties of the error object
39 | *
40 | * These represent property names that are added to javascript `Error` objects
41 | * generated by mapserver.
42 | *
43 | * @{
44 | */
45 | Persistent MapserverError::name_symbol;
46 | Persistent MapserverError::code_symbol;
47 | Persistent MapserverError::category_symbol;
48 | Persistent MapserverError::routine_symbol;
49 | Persistent MapserverError::isReported_symbol;
50 | Persistent MapserverError::errorStack_symbol;
51 | /**@}*/
52 |
53 |
54 | /**
55 | * @details This is called from the module initialisation function
56 | * when the module is first loaded by Node. It should only be called
57 | * once per process.
58 | */
59 | void MapserverError::Init() {
60 | // initialise the persistent strings
61 | MapserverError_symbol = NODE_PSYMBOL("MapserverError");
62 |
63 | name_symbol = NODE_PSYMBOL("name");
64 | code_symbol = NODE_PSYMBOL("code");
65 | category_symbol = NODE_PSYMBOL("category");
66 | routine_symbol = NODE_PSYMBOL("routine");
67 | isReported_symbol = NODE_PSYMBOL("isReported");
68 | errorStack_symbol = NODE_PSYMBOL("errorStack");
69 | }
70 |
71 | /**
72 | * @details A constructor that builds from a standard mapserver `errorObj`.
73 | * This effectively copies the mapserver data structure.
74 | *
75 | * @param error A mapserver `errorObj`.
76 | */
77 | MapserverError::MapserverError(const errorObj *error) {
78 | MapserverError *copy = this;
79 | length = 0;
80 | while (error) {
81 | copy->code = error->code;
82 | copy->routine = error->routine;
83 | copy->message = error->message;
84 | copy->isReported = error->isreported;
85 | if (error->next) {
86 | copy->next = new MapserverError();
87 | copy = copy->next;
88 | }
89 | error = error->next;
90 | length++;
91 | }
92 | copy->next = NULL;
93 | }
94 |
95 | /**
96 | * @details This returns a representation of the `MapserverError` instance as a
97 | * V8 exception. The internal linked list implementing the error stack is
98 | * converted to a Javascript Array.
99 | */
100 | Handle MapserverError::toV8Error() {
101 | HandleScope scope;
102 |
103 | // Represent the error stack linked list as an array
104 | MapserverError *error = next;
105 | unsigned int i = 0;
106 | Local errorStack = Array::New(length-1);
107 | while (error) {
108 | Handle exception = ToV8Error(error);
109 | errorStack->Set(i++, exception); // add the error to the stack
110 | error = error->next;
111 | }
112 |
113 | // Create an error representing the current error
114 | Handle result = ToV8Error(this);
115 | result->ToObject()->Set(errorStack_symbol, errorStack); // add the stack to the current error
116 |
117 | return scope.Close(result);
118 | }
119 |
120 | /**
121 | * @detail A class method that converts a `MapserverError` to a V8 exception.
122 | * This only operates on the error properties and does not process the internal
123 | * linked list.
124 | *
125 | * @param error The `MapserverError` pointer.
126 | */
127 | Handle MapserverError::ToV8Error(MapserverError *error) {
128 | HandleScope scope;
129 |
130 | char *category = msGetErrorCodeString(error->code);
131 | Local result = Exception::Error(String::New(( error->message.length() ? error->message.c_str() : category )));
132 | Local