Line data Source code
1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: WMS Client Driver
5 : * Purpose: Implementation of Dataset and RasterBand classes for WMS
6 : * and other similar services.
7 : * Author: Adam Nowacki, nowak@xpam.de
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2007, Adam Nowacki
11 : * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
12 : * Copyright (c) 2017, Dmitry Baryshnikov, <polimax@mail.ru>
13 : * Copyright (c) 2017, NextGIS, <info@nextgis.com>
14 : *
15 : * SPDX-License-Identifier: MIT
16 : ****************************************************************************/
17 :
18 : #ifndef WMSDRIVER_H_INCLUDED
19 : #define WMSDRIVER_H_INCLUDED
20 :
21 : #include <algorithm>
22 : #include <cmath>
23 : #include <map>
24 : #include <set>
25 : #include <vector>
26 : #include <utility>
27 :
28 : #include "cpl_conv.h"
29 : #include "cpl_curl_priv.h"
30 : #include "cpl_http.h"
31 : #include "gdal_alg.h"
32 : #include "gdal_pam.h"
33 : #include "gdalwarper.h"
34 : #include "ogr_spatialref.h"
35 :
36 : #include "gdalhttp.h"
37 :
38 : class GDALWMSDataset;
39 : class GDALWMSRasterBand;
40 :
41 : /* -------------------------------------------------------------------- */
42 : /* Helper functions. */
43 : /* -------------------------------------------------------------------- */
44 : OGRSpatialReference ProjToSRS(const CPLString &proj);
45 :
46 : // Decode s from encoding "base64" or "XMLencoded".
47 : // If encoding is "file", s is the file name on input and file content on output
48 : // If encoding is not recognized, does nothing
49 : const char *WMSUtilDecode(CPLString &s, const char *encoding);
50 :
51 : // Ensure that the url ends in ? or &
52 : void URLPrepare(CPLString &url);
53 : // void URLAppend(CPLString *url, const char *s);
54 : // void URLAppendF(CPLString *url, const char *s, ...) CPL_PRINT_FUNC_FORMAT (2,
55 : // 3); void URLAppend(CPLString *url, const CPLString &s);
56 : CPLString BufferToVSIFile(GByte *buffer, size_t size);
57 :
58 : int StrToBool(const char *p);
59 : int URLSearchAndReplace(CPLString *base, const char *search, const char *fmt,
60 : ...) CPL_PRINT_FUNC_FORMAT(3, 4);
61 : /* Convert a.b.c.d to a * 0x1000000 + b * 0x10000 + c * 0x100 + d */
62 : int VersionStringToInt(const char *version);
63 :
64 : class GDALWMSImageRequestInfo
65 : {
66 : public:
67 : double m_x0, m_y0;
68 : double m_x1, m_y1;
69 : int m_sx, m_sy;
70 : };
71 :
72 : class GDALWMSDataWindow
73 : {
74 : public:
75 : double m_x0, m_y0;
76 : double m_x1, m_y1;
77 : int m_sx, m_sy;
78 : int m_tx, m_ty, m_tlevel;
79 :
80 : enum
81 : {
82 : BOTTOM = -1,
83 : DEFAULT = 0,
84 : TOP = 1
85 : } m_y_origin;
86 :
87 702 : GDALWMSDataWindow()
88 702 : : m_x0(-180), m_y0(90), m_x1(180), m_y1(-90), m_sx(-1), m_sy(-1),
89 702 : m_tx(0), m_ty(0), m_tlevel(-1), m_y_origin(DEFAULT)
90 : {
91 702 : }
92 : };
93 :
94 : class GDALWMSTiledImageRequestInfo
95 : {
96 : public:
97 : int m_x, m_y;
98 : int m_level;
99 : };
100 :
101 : /************************************************************************/
102 : /* Mini Driver Related */
103 : /************************************************************************/
104 :
105 : class GDALWMSRasterIOHint
106 : {
107 : public:
108 349 : GDALWMSRasterIOHint()
109 349 : : m_x0(0), m_y0(0), m_sx(0), m_sy(0), m_overview(0), m_valid(false)
110 : {
111 349 : }
112 :
113 : int m_x0;
114 : int m_y0;
115 : int m_sx;
116 : int m_sy;
117 : int m_overview;
118 : bool m_valid;
119 : };
120 :
121 : typedef enum
122 : {
123 : OVERVIEW_ROUNDED,
124 : OVERVIEW_FLOOR
125 : } GDALWMSOverviewDimComputationMethod;
126 :
127 : class WMSMiniDriverCapabilities
128 : {
129 : public:
130 : // Default capabilities, suitable in most cases
131 349 : WMSMiniDriverCapabilities()
132 349 : : m_has_getinfo(0), m_has_geotransform(1),
133 349 : m_overview_dim_computation_method(OVERVIEW_ROUNDED)
134 : {
135 349 : }
136 :
137 : int m_has_getinfo; // Does it have meaningful implementation
138 : int m_has_geotransform;
139 : GDALWMSOverviewDimComputationMethod m_overview_dim_computation_method;
140 : };
141 :
142 : /* All data returned by mini-driver as pointer should remain valid for
143 : mini-driver lifetime and should be freed by mini-driver destructor unless
144 : otherwise specified.
145 : */
146 :
147 : // Base class for minidrivers
148 : // A minidriver has to implement at least the Initialize and the
149 : // TiledImageRequest
150 : //
151 : class WMSMiniDriver
152 : {
153 : friend class GDALWMSDataset;
154 :
155 : public:
156 348 : WMSMiniDriver() : m_parent_dataset(nullptr)
157 : {
158 348 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
159 348 : }
160 :
161 348 : virtual ~WMSMiniDriver()
162 348 : {
163 348 : }
164 :
165 : public:
166 : // MiniDriver specific initialization from XML, required
167 : // Called once at the beginning of the dataset initialization
168 : virtual CPLErr Initialize(CPLXMLNode *config, char **papszOpenOptions) = 0;
169 :
170 : // Called once at the end of the dataset initialization
171 347 : virtual CPLErr EndInit()
172 : {
173 347 : return CE_None;
174 : }
175 :
176 : // Error message returned in url, required
177 : // Set error message in request.Error
178 : // If tile doesn't exist serverside, set request.range to "none"
179 : virtual CPLErr
180 : TiledImageRequest(CPL_UNUSED WMSHTTPRequest &,
181 : CPL_UNUSED const GDALWMSImageRequestInfo &iri,
182 : CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri) = 0;
183 :
184 : // change capabilities to be used by the parent
185 340 : virtual void GetCapabilities(CPL_UNUSED WMSMiniDriverCapabilities *caps)
186 : {
187 340 : }
188 :
189 : // signal by setting the m_has_getinfo in the GetCapabilities call
190 : virtual void
191 0 : GetTiledImageInfo(CPL_UNUSED CPLString &url,
192 : CPL_UNUSED const GDALWMSImageRequestInfo &iri,
193 : CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri,
194 : CPL_UNUSED int nXInBlock, CPL_UNUSED int nYInBlock)
195 : {
196 0 : }
197 :
198 187 : virtual OGRSpatialReference GetSpatialRef()
199 : {
200 187 : return m_oSRS;
201 : }
202 :
203 0 : virtual char **GetMetadataDomainList()
204 : {
205 0 : return nullptr;
206 : }
207 :
208 : protected:
209 : CPLString m_base_url;
210 : OGRSpatialReference m_oSRS;
211 : GDALWMSDataset *m_parent_dataset;
212 : };
213 :
214 : class WMSMiniDriverFactory
215 : {
216 : public:
217 99 : WMSMiniDriverFactory()
218 99 : {
219 99 : }
220 :
221 99 : virtual ~WMSMiniDriverFactory()
222 99 : {
223 99 : }
224 :
225 : public:
226 : virtual WMSMiniDriver *New() const = 0;
227 : CPLString m_name;
228 : };
229 :
230 : // Interface with the global mini driver manager
231 : WMSMiniDriver *NewWMSMiniDriver(const CPLString &name);
232 : void WMSRegisterMiniDriverFactory(WMSMiniDriverFactory *mdf);
233 : void WMSDeregisterMiniDrivers(GDALDriver *);
234 :
235 : // WARNING: Called by GDALDestructor, unsafe to use any static objects
236 : void WMSDeregister(GDALDriver *);
237 :
238 : /************************************************************************/
239 : /* GDALWMSCache */
240 : /************************************************************************/
241 : enum GDALWMSCacheItemStatus
242 : {
243 : CACHE_ITEM_NOT_FOUND,
244 : CACHE_ITEM_OK,
245 : CACHE_ITEM_EXPIRED
246 : };
247 :
248 : class GDALWMSCacheImpl
249 : {
250 : public:
251 213 : GDALWMSCacheImpl(const CPLString &soPath, CPLXMLNode * /*pConfig*/)
252 213 : : m_soPath(soPath)
253 : {
254 213 : }
255 :
256 213 : virtual ~GDALWMSCacheImpl()
257 213 : {
258 213 : }
259 :
260 : virtual CPLErr Insert(const char *pszKey, const CPLString &osFileName) = 0;
261 : virtual enum GDALWMSCacheItemStatus
262 : GetItemStatus(const char *pszKey) const = 0;
263 : virtual GDALDataset *GetDataset(const char *pszKey,
264 : char **papszOpenOptions) const = 0;
265 : virtual void Clean() = 0;
266 : virtual int GetCleanThreadRunTimeout() = 0;
267 :
268 : protected:
269 : CPLString m_soPath;
270 : };
271 :
272 213 : class GDALWMSCache
273 : {
274 : friend class GDALWMSDataset;
275 :
276 : public:
277 : GDALWMSCache();
278 : ~GDALWMSCache();
279 :
280 : public:
281 : CPLErr Initialize(const char *pszUrl, CPLXMLNode *pConfig);
282 : CPLErr Insert(const char *pszKey, const CPLString &osFileName);
283 : enum GDALWMSCacheItemStatus GetItemStatus(const char *pszKey) const;
284 : GDALDataset *GetDataset(const char *pszKey, char **papszOpenOptions) const;
285 : void Clean();
286 :
287 : protected:
288 213 : CPLString CachePath() const
289 : {
290 213 : return m_osCachePath;
291 : }
292 :
293 : protected:
294 : CPLString m_osCachePath{};
295 : bool m_bIsCleanThreadRunning = false;
296 : time_t m_nCleanThreadLastRunTime = 0;
297 :
298 : private:
299 : GDALWMSCacheImpl *m_poCache = nullptr;
300 : CPLJoinableThread *m_hThread = nullptr;
301 : };
302 :
303 : /************************************************************************/
304 : /* GDALWMSDataset */
305 : /************************************************************************/
306 :
307 : class GDALWMSDataset final : public GDALPamDataset
308 : {
309 : friend class GDALWMSRasterBand;
310 :
311 : public:
312 : GDALWMSDataset();
313 : virtual ~GDALWMSDataset();
314 :
315 : const OGRSpatialReference *GetSpatialRef() const override;
316 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
317 :
318 : virtual CPLErr GetGeoTransform(double *gt) override;
319 : virtual CPLErr SetGeoTransform(double *gt) override;
320 : virtual CPLErr AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy,
321 : GDALDataType bdt, int band_count, int *band_map,
322 : char **options) override;
323 :
324 : virtual char **GetMetadataDomainList() override;
325 : virtual const char *GetMetadataItem(const char *pszName,
326 : const char *pszDomain = "") override;
327 :
328 0 : void SetColorTable(GDALColorTable *pct)
329 : {
330 0 : m_poColorTable = pct;
331 0 : }
332 :
333 9 : void mSetBand(int i, GDALRasterBand *band)
334 : {
335 9 : SetBand(i, band);
336 9 : }
337 :
338 72 : GDALWMSRasterBand *mGetBand(int i)
339 : {
340 72 : return reinterpret_cast<GDALWMSRasterBand *>(GetRasterBand(i));
341 : }
342 :
343 48 : const GDALWMSDataWindow *WMSGetDataWindow() const
344 : {
345 48 : return &m_data_window;
346 : }
347 :
348 3 : void WMSSetBlockSize(int x, int y)
349 : {
350 3 : m_block_size_x = x;
351 3 : m_block_size_y = y;
352 3 : }
353 :
354 3 : void WMSSetRasterSize(int x, int y)
355 : {
356 3 : nRasterXSize = x;
357 3 : nRasterYSize = y;
358 3 : }
359 :
360 3 : void WMSSetBandsCount(int count)
361 : {
362 3 : nBands = count;
363 3 : }
364 :
365 3 : void WMSSetClamp(bool flag = true)
366 : {
367 3 : m_clamp_requests = flag;
368 3 : }
369 :
370 3 : void WMSSetDataType(GDALDataType type)
371 : {
372 3 : m_data_type = type;
373 3 : }
374 :
375 3 : void WMSSetDataWindow(const GDALWMSDataWindow &window)
376 : {
377 3 : m_data_window = window;
378 3 : }
379 :
380 1 : void WMSSetDefaultBlockSize(int x, int y)
381 : {
382 1 : m_default_block_size_x = x;
383 1 : m_default_block_size_y = y;
384 1 : }
385 :
386 1 : void WMSSetDefaultDataWindowCoordinates(double x0, double y0, double x1,
387 : double y1)
388 : {
389 1 : m_default_data_window.m_x0 = x0;
390 1 : m_default_data_window.m_y0 = y0;
391 1 : m_default_data_window.m_x1 = x1;
392 1 : m_default_data_window.m_y1 = y1;
393 1 : }
394 :
395 0 : void WMSSetDefaultTileCount(int tilecountx, int tilecounty)
396 : {
397 0 : m_default_tile_count_x = tilecountx;
398 0 : m_default_tile_count_y = tilecounty;
399 0 : }
400 :
401 1 : void WMSSetDefaultTileLevel(int tlevel)
402 : {
403 1 : m_default_data_window.m_tlevel = tlevel;
404 1 : }
405 :
406 1 : void WMSSetDefaultOverviewCount(int overview_count)
407 : {
408 1 : m_default_overview_count = overview_count;
409 1 : }
410 :
411 1 : void WMSSetNeedsDataWindow(bool flag)
412 : {
413 1 : m_bNeedsDataWindow = flag;
414 1 : }
415 :
416 3 : static void list2vec(std::vector<double> &v, const char *pszList)
417 : {
418 3 : if ((pszList == nullptr) || (pszList[0] == 0))
419 0 : return;
420 3 : char **papszTokens = CSLTokenizeString2(
421 : pszList, " \t\n\r", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
422 3 : v.clear();
423 6 : for (int i = 0; i < CSLCount(papszTokens); i++)
424 3 : v.push_back(CPLStrtod(papszTokens[i], nullptr));
425 3 : CSLDestroy(papszTokens);
426 : }
427 :
428 3 : void WMSSetNoDataValue(const char *pszNoData)
429 : {
430 3 : list2vec(vNoData, pszNoData);
431 3 : }
432 :
433 0 : void WMSSetMinValue(const char *pszMin)
434 : {
435 0 : list2vec(vMin, pszMin);
436 0 : }
437 :
438 0 : void WMSSetMaxValue(const char *pszMax)
439 : {
440 0 : list2vec(vMax, pszMax);
441 0 : }
442 :
443 : // Set open options for tiles
444 : // Works like a <set>, only one entry with a give name can exist, last one
445 : // set wins If the value is null, the entry is deleted
446 : void SetTileOO(const char *pszName, const char *pszValue);
447 :
448 2 : void SetXML(const char *psz)
449 : {
450 2 : m_osXML.clear();
451 2 : if (psz)
452 2 : m_osXML = psz;
453 2 : }
454 :
455 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
456 : static GDALDataset *CreateCopy(const char *pszFilename,
457 : GDALDataset *poSrcDS, int bStrict,
458 : char **papszOptions,
459 : GDALProgressFunc pfnProgress,
460 : void *pProgressData);
461 :
462 : const char *const *GetHTTPRequestOpts();
463 :
464 : static const char *GetServerConfig(const char *URI,
465 : char **papszHTTPOptions);
466 : static void DestroyCfgMutex();
467 : static void ClearConfigCache();
468 :
469 : protected:
470 : virtual CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
471 : void *buffer, int bsx, int bsy, GDALDataType bdt,
472 : int band_count, BANDMAP_TYPE band_map,
473 : GSpacing nPixelSpace, GSpacing nLineSpace,
474 : GSpacing nBandSpace,
475 : GDALRasterIOExtraArg *psExtraArg) override;
476 : CPLErr Initialize(CPLXMLNode *config, char **papszOpenOptions);
477 :
478 : GDALWMSDataWindow m_data_window;
479 : WMSMiniDriver *m_mini_driver;
480 : WMSMiniDriverCapabilities m_mini_driver_caps;
481 : GDALWMSCache *m_cache;
482 : OGRSpatialReference m_oSRS{};
483 : GDALColorTable *m_poColorTable;
484 : std::vector<double> vNoData;
485 : std::vector<double> vMin;
486 : std::vector<double> vMax;
487 : GDALDataType m_data_type;
488 : int m_block_size_x;
489 : int m_block_size_y;
490 : GDALWMSRasterIOHint m_hint;
491 : int m_use_advise_read;
492 : int m_verify_advise_read;
493 : int m_offline_mode;
494 : int m_http_max_conn;
495 : int m_http_timeout;
496 : char **m_http_options;
497 : // Open Option list for tiles
498 : char **m_tileOO;
499 : int m_clamp_requests;
500 : int m_unsafeSsl;
501 : std::set<int> m_http_zeroblock_codes;
502 : int m_zeroblock_on_serverexceptions;
503 : CPLString m_osUserAgent;
504 : CPLString m_osReferer;
505 : CPLString m_osUserPwd;
506 : std::string m_osAccept{}; // HTTP Accept header
507 :
508 : GDALWMSDataWindow m_default_data_window;
509 : int m_default_block_size_x;
510 : int m_default_block_size_y;
511 : int m_default_tile_count_x;
512 : int m_default_tile_count_y;
513 : int m_default_overview_count;
514 :
515 : bool m_bNeedsDataWindow;
516 :
517 : CPLString m_osXML;
518 :
519 : // Per session cache of server configurations
520 : typedef std::map<CPLString, CPLString> StringMap_t;
521 : static CPLMutex *cfgmtx;
522 : static StringMap_t cfg;
523 : };
524 :
525 : /************************************************************************/
526 : /* GDALWMSRasterBand */
527 : /************************************************************************/
528 :
529 : class GDALWMSRasterBand final : public GDALPamRasterBand
530 : {
531 : friend class GDALWMSDataset;
532 : void ComputeRequestInfo(GDALWMSImageRequestInfo &iri,
533 : GDALWMSTiledImageRequestInfo &tiri, int x, int y);
534 :
535 : CPLString osMetadataItem;
536 : CPLString osMetadataItemURL;
537 :
538 : public:
539 : GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band, double scale);
540 : virtual ~GDALWMSRasterBand();
541 : bool AddOverview(double scale);
542 : virtual double GetNoDataValue(int *) override;
543 : virtual double GetMinimum(int *) override;
544 : virtual double GetMaximum(int *) override;
545 : virtual GDALColorTable *GetColorTable() override;
546 : virtual CPLErr AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy,
547 : GDALDataType bdt, char **options) override;
548 :
549 : virtual GDALColorInterp GetColorInterpretation() override;
550 : virtual CPLErr SetColorInterpretation(GDALColorInterp) override;
551 : virtual CPLErr IReadBlock(int x, int y, void *buffer) override;
552 : virtual CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
553 : void *buffer, int bsx, int bsy, GDALDataType bdt,
554 : GSpacing nPixelSpace, GSpacing nLineSpace,
555 : GDALRasterIOExtraArg *psExtraArg) override;
556 : virtual int HasArbitraryOverviews() override;
557 : virtual int GetOverviewCount() override;
558 : virtual GDALRasterBand *GetOverview(int n) override;
559 :
560 : virtual char **GetMetadataDomainList() override;
561 : virtual const char *GetMetadataItem(const char *pszName,
562 : const char *pszDomain = "") override;
563 :
564 : protected:
565 : CPLErr ReadBlocks(int x, int y, void *buffer, int bx0, int by0, int bx1,
566 : int by1, int advise_read);
567 : bool IsBlockInCache(int x, int y);
568 : CPLErr AskMiniDriverForBlock(WMSHTTPRequest &request, int x, int y);
569 : CPLErr ReadBlockFromCache(const char *pszKey, int x, int y,
570 : int to_buffer_band, void *buffer,
571 : int advise_read);
572 : CPLErr ReadBlockFromFile(const CPLString &soFileName, int x, int y,
573 : int to_buffer_band, void *buffer, int advise_read);
574 : CPLErr ReadBlockFromDataset(GDALDataset *ds, int x, int y,
575 : int to_buffer_band, void *buffer,
576 : int advise_read);
577 : CPLErr EmptyBlock(int x, int y, int to_buffer_band, void *buffer);
578 : static CPLErr ReportWMSException(const char *file_name);
579 :
580 : protected:
581 : GDALWMSDataset *m_parent_dataset;
582 : double m_scale;
583 : std::vector<GDALWMSRasterBand *> m_overviews;
584 : int m_overview;
585 : GDALColorInterp m_color_interp;
586 : int m_nAdviseReadBX0;
587 : int m_nAdviseReadBY0;
588 : int m_nAdviseReadBX1;
589 : int m_nAdviseReadBY1;
590 : };
591 :
592 : #endif /* notdef WMSDRIVER_H_INCLUDED */
|