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