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 /* non final */
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 /* non final */
211 : {
212 : public:
213 : virtual ~WMSMiniDriverFactory();
214 : virtual WMSMiniDriver *New() const = 0;
215 : CPLString m_name{};
216 :
217 : protected:
218 120 : WMSMiniDriverFactory() = default;
219 : };
220 :
221 : // Interface with the global mini driver manager
222 : WMSMiniDriver *NewWMSMiniDriver(const CPLString &name);
223 : void WMSRegisterMiniDriverFactory(WMSMiniDriverFactory *mdf);
224 : void WMSDeregisterMiniDrivers(GDALDriver *);
225 :
226 : // WARNING: Called by GDALDestructor, unsafe to use any static objects
227 : void WMSDeregister(GDALDriver *);
228 :
229 : /************************************************************************/
230 : /* GDALWMSCache */
231 : /************************************************************************/
232 : enum GDALWMSCacheItemStatus
233 : {
234 : CACHE_ITEM_NOT_FOUND,
235 : CACHE_ITEM_OK,
236 : CACHE_ITEM_EXPIRED
237 : };
238 :
239 217 : class GDALWMSCacheImpl /* non final */
240 : {
241 : public:
242 217 : GDALWMSCacheImpl(const CPLString &soPath, CPLXMLNode * /*pConfig*/)
243 217 : : m_soPath(soPath)
244 : {
245 217 : }
246 :
247 : virtual ~GDALWMSCacheImpl();
248 :
249 : virtual CPLErr Insert(const char *pszKey, const CPLString &osFileName) = 0;
250 : virtual enum GDALWMSCacheItemStatus
251 : GetItemStatus(const char *pszKey) const = 0;
252 : virtual GDALDataset *GetDataset(const char *pszKey,
253 : char **papszOpenOptions) const = 0;
254 : virtual void Clean() = 0;
255 : virtual int GetCleanThreadRunTimeout() = 0;
256 :
257 : protected:
258 : CPLString m_soPath;
259 : };
260 :
261 217 : class GDALWMSCache final
262 : {
263 : friend class GDALWMSDataset;
264 :
265 : public:
266 : GDALWMSCache();
267 : ~GDALWMSCache();
268 :
269 : public:
270 : CPLErr Initialize(const char *pszUrl, CPLXMLNode *pConfig);
271 : CPLErr Insert(const char *pszKey, const CPLString &osFileName);
272 : enum GDALWMSCacheItemStatus GetItemStatus(const char *pszKey) const;
273 : GDALDataset *GetDataset(const char *pszKey, char **papszOpenOptions) const;
274 : void Clean();
275 :
276 : protected:
277 217 : CPLString CachePath() const
278 : {
279 217 : return m_osCachePath;
280 : }
281 :
282 : protected:
283 : CPLString m_osCachePath{};
284 : bool m_bIsCleanThreadRunning = false;
285 : time_t m_nCleanThreadLastRunTime = 0;
286 :
287 : private:
288 : GDALWMSCacheImpl *m_poCache = nullptr;
289 : CPLJoinableThread *m_hThread = nullptr;
290 :
291 : CPL_DISALLOW_COPY_ASSIGN(GDALWMSCache)
292 : };
293 :
294 : /************************************************************************/
295 : /* GDALWMSDataset */
296 : /************************************************************************/
297 :
298 : class GDALWMSDataset final : public GDALPamDataset
299 : {
300 : friend class GDALWMSRasterBand;
301 :
302 : CPL_DISALLOW_COPY_ASSIGN(GDALWMSDataset)
303 :
304 : public:
305 : GDALWMSDataset();
306 : ~GDALWMSDataset() override;
307 :
308 : const OGRSpatialReference *GetSpatialRef() const override;
309 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
310 :
311 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
312 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
313 : CPLErr AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy,
314 : GDALDataType bdt, int band_count, int *band_map,
315 : char **options) override;
316 :
317 : char **GetMetadataDomainList() override;
318 : virtual const char *GetMetadataItem(const char *pszName,
319 : const char *pszDomain = "") override;
320 :
321 0 : void SetColorTable(GDALColorTable *pct)
322 : {
323 0 : m_poColorTable = pct;
324 0 : }
325 :
326 9 : void mSetBand(int i, GDALRasterBand *band)
327 : {
328 9 : SetBand(i, band);
329 9 : }
330 :
331 72 : GDALWMSRasterBand *mGetBand(int i)
332 : {
333 72 : return reinterpret_cast<GDALWMSRasterBand *>(GetRasterBand(i));
334 : }
335 :
336 48 : const GDALWMSDataWindow *WMSGetDataWindow() const
337 : {
338 48 : return &m_data_window;
339 : }
340 :
341 3 : void WMSSetBlockSize(int x, int y)
342 : {
343 3 : m_block_size_x = x;
344 3 : m_block_size_y = y;
345 3 : }
346 :
347 3 : void WMSSetRasterSize(int x, int y)
348 : {
349 3 : nRasterXSize = x;
350 3 : nRasterYSize = y;
351 3 : }
352 :
353 3 : void WMSSetBandsCount(int count)
354 : {
355 3 : nBands = count;
356 3 : }
357 :
358 3 : void WMSSetClamp(bool flag = true)
359 : {
360 3 : m_clamp_requests = flag;
361 3 : }
362 :
363 3 : void WMSSetDataType(GDALDataType type)
364 : {
365 3 : m_data_type = type;
366 3 : }
367 :
368 3 : void WMSSetDataWindow(const GDALWMSDataWindow &window)
369 : {
370 3 : m_data_window = window;
371 3 : }
372 :
373 1 : void WMSSetDefaultBlockSize(int x, int y)
374 : {
375 1 : m_default_block_size_x = x;
376 1 : m_default_block_size_y = y;
377 1 : }
378 :
379 1 : void WMSSetDefaultDataWindowCoordinates(double x0, double y0, double x1,
380 : double y1)
381 : {
382 1 : m_default_data_window.m_x0 = x0;
383 1 : m_default_data_window.m_y0 = y0;
384 1 : m_default_data_window.m_x1 = x1;
385 1 : m_default_data_window.m_y1 = y1;
386 1 : }
387 :
388 0 : void WMSSetDefaultTileCount(int tilecountx, int tilecounty)
389 : {
390 0 : m_default_tile_count_x = tilecountx;
391 0 : m_default_tile_count_y = tilecounty;
392 0 : }
393 :
394 1 : void WMSSetDefaultTileLevel(int tlevel)
395 : {
396 1 : m_default_data_window.m_tlevel = tlevel;
397 1 : }
398 :
399 1 : void WMSSetDefaultOverviewCount(int overview_count)
400 : {
401 1 : m_default_overview_count = overview_count;
402 1 : }
403 :
404 1 : void WMSSetNeedsDataWindow(bool flag)
405 : {
406 1 : m_bNeedsDataWindow = flag;
407 1 : }
408 :
409 3 : static void list2vec(std::vector<double> &v, const char *pszList)
410 : {
411 3 : if ((pszList == nullptr) || (pszList[0] == 0))
412 0 : return;
413 3 : char **papszTokens = CSLTokenizeString2(
414 : pszList, " \t\n\r", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
415 3 : v.clear();
416 6 : for (int i = 0; i < CSLCount(papszTokens); i++)
417 3 : v.push_back(CPLStrtod(papszTokens[i], nullptr));
418 3 : CSLDestroy(papszTokens);
419 : }
420 :
421 3 : void WMSSetNoDataValue(const char *pszNoData)
422 : {
423 3 : list2vec(vNoData, pszNoData);
424 3 : }
425 :
426 0 : void WMSSetMinValue(const char *pszMin)
427 : {
428 0 : list2vec(vMin, pszMin);
429 0 : }
430 :
431 0 : void WMSSetMaxValue(const char *pszMax)
432 : {
433 0 : list2vec(vMax, pszMax);
434 0 : }
435 :
436 : // Set open options for tiles
437 : // Works like a <set>, only one entry with a give name can exist, last one
438 : // set wins If the value is null, the entry is deleted
439 : void SetTileOO(const char *pszName, const char *pszValue);
440 :
441 2 : void SetXML(const char *psz)
442 : {
443 2 : m_osXML.clear();
444 2 : if (psz)
445 2 : m_osXML = psz;
446 2 : }
447 :
448 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
449 : static GDALDataset *CreateCopy(const char *pszFilename,
450 : GDALDataset *poSrcDS, int bStrict,
451 : char **papszOptions,
452 : GDALProgressFunc pfnProgress,
453 : void *pProgressData);
454 :
455 : const char *const *GetHTTPRequestOpts();
456 :
457 : static const char *GetServerConfig(const char *URI,
458 : char **papszHTTPOptions);
459 : static void DestroyCfgMutex();
460 : static void ClearConfigCache();
461 :
462 : protected:
463 : CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
464 : void *buffer, int bsx, int bsy, GDALDataType bdt,
465 : int band_count, BANDMAP_TYPE band_map,
466 : GSpacing nPixelSpace, GSpacing nLineSpace,
467 : GSpacing nBandSpace,
468 : GDALRasterIOExtraArg *psExtraArg) override;
469 : CPLErr Initialize(CPLXMLNode *config, char **papszOpenOptions);
470 :
471 : GDALWMSDataWindow m_data_window{};
472 : WMSMiniDriver *m_mini_driver{};
473 : WMSMiniDriverCapabilities m_mini_driver_caps{};
474 : GDALWMSCache *m_cache{};
475 : OGRSpatialReference m_oSRS{};
476 : GDALColorTable *m_poColorTable{};
477 : std::vector<double> vNoData{};
478 : std::vector<double> vMin{};
479 : std::vector<double> vMax{};
480 : GDALDataType m_data_type{GDT_Unknown};
481 : int m_block_size_x{};
482 : int m_block_size_y{};
483 : GDALWMSRasterIOHint m_hint{};
484 : int m_use_advise_read{};
485 : int m_verify_advise_read{};
486 : int m_offline_mode{};
487 : int m_http_max_conn{};
488 : int m_http_timeout{};
489 : char **m_http_options{};
490 : // Open Option list for tiles
491 : char **m_tileOO{};
492 : int m_clamp_requests{};
493 : int m_unsafeSsl{};
494 : std::set<int> m_http_zeroblock_codes{};
495 : int m_zeroblock_on_serverexceptions{};
496 : CPLString m_osUserAgent{};
497 : CPLString m_osReferer{};
498 : CPLString m_osUserPwd{};
499 : std::string m_osAccept{}; // HTTP Accept header
500 :
501 : GDALWMSDataWindow m_default_data_window{};
502 : int m_default_block_size_x{};
503 : int m_default_block_size_y{};
504 : int m_default_tile_count_x{};
505 : int m_default_tile_count_y{};
506 : int m_default_overview_count{};
507 :
508 : bool m_bNeedsDataWindow{};
509 :
510 : CPLString m_osXML{};
511 :
512 : // Per session cache of server configurations
513 : typedef std::map<CPLString, CPLString> StringMap_t;
514 : static CPLMutex *cfgmtx;
515 : static StringMap_t cfg;
516 : };
517 :
518 : /************************************************************************/
519 : /* GDALWMSRasterBand */
520 : /************************************************************************/
521 :
522 : class GDALWMSRasterBand final : public GDALPamRasterBand
523 : {
524 : friend class GDALWMSDataset;
525 : void ComputeRequestInfo(GDALWMSImageRequestInfo &iri,
526 : GDALWMSTiledImageRequestInfo &tiri, int x, int y);
527 :
528 : CPLString osMetadataItem{};
529 : CPLString osMetadataItemURL{};
530 :
531 : CPL_DISALLOW_COPY_ASSIGN(GDALWMSRasterBand)
532 :
533 : public:
534 : GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band, double scale);
535 : ~GDALWMSRasterBand() override;
536 : bool AddOverview(double scale);
537 : double GetNoDataValue(int *) override;
538 : double GetMinimum(int *) override;
539 : double GetMaximum(int *) override;
540 : GDALColorTable *GetColorTable() override;
541 : CPLErr AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy,
542 : GDALDataType bdt, char **options) override;
543 :
544 : GDALColorInterp GetColorInterpretation() override;
545 : CPLErr SetColorInterpretation(GDALColorInterp) override;
546 : CPLErr IReadBlock(int x, int y, void *buffer) override;
547 : CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
548 : void *buffer, int bsx, int bsy, GDALDataType bdt,
549 : GSpacing nPixelSpace, GSpacing nLineSpace,
550 : GDALRasterIOExtraArg *psExtraArg) override;
551 : int HasArbitraryOverviews() override;
552 : int GetOverviewCount() override;
553 : GDALRasterBand *GetOverview(int n) override;
554 :
555 : char **GetMetadataDomainList() override;
556 : virtual const char *GetMetadataItem(const char *pszName,
557 : const char *pszDomain = "") override;
558 :
559 : protected:
560 : CPLErr ReadBlocks(int x, int y, void *buffer, int bx0, int by0, int bx1,
561 : int by1, int advise_read);
562 : bool IsBlockInCache(int x, int y);
563 : CPLErr AskMiniDriverForBlock(WMSHTTPRequest &request, int x, int y);
564 : CPLErr ReadBlockFromCache(const char *pszKey, int x, int y,
565 : int to_buffer_band, void *buffer,
566 : int advise_read);
567 : CPLErr ReadBlockFromFile(const CPLString &soFileName, int x, int y,
568 : int to_buffer_band, void *buffer, int advise_read);
569 : CPLErr ReadBlockFromDataset(GDALDataset *ds, int x, int y,
570 : int to_buffer_band, void *buffer,
571 : int advise_read);
572 : CPLErr EmptyBlock(int x, int y, int to_buffer_band, void *buffer);
573 : static CPLErr ReportWMSException(const char *file_name);
574 :
575 : protected:
576 : GDALWMSDataset *m_parent_dataset{};
577 : double m_scale{};
578 : std::vector<GDALWMSRasterBand *> m_overviews{};
579 : int m_overview{};
580 : GDALColorInterp m_color_interp{};
581 : int m_nAdviseReadBX0{};
582 : int m_nAdviseReadBY0{};
583 : int m_nAdviseReadBX1{};
584 : int m_nAdviseReadBY1{};
585 : };
586 :
587 : #endif /* notdef WMSDRIVER_H_INCLUDED */
|