MapProxy 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. MapProxy-2.1.0.dist-info/AUTHORS.txt +33 -0
  2. MapProxy-2.1.0.dist-info/COPYING.txt +60 -0
  3. MapProxy-2.1.0.dist-info/LICENSE.txt +202 -0
  4. MapProxy-2.1.0.dist-info/METADATA +165 -0
  5. MapProxy-2.1.0.dist-info/RECORD +459 -0
  6. MapProxy-2.1.0.dist-info/WHEEL +5 -0
  7. MapProxy-2.1.0.dist-info/entry_points.txt +4 -0
  8. MapProxy-2.1.0.dist-info/top_level.txt +1 -0
  9. mapproxy/__init__.py +0 -0
  10. mapproxy/cache/__init__.py +36 -0
  11. mapproxy/cache/azureblob.py +145 -0
  12. mapproxy/cache/base.py +120 -0
  13. mapproxy/cache/compact.py +665 -0
  14. mapproxy/cache/couchdb.py +301 -0
  15. mapproxy/cache/dummy.py +36 -0
  16. mapproxy/cache/file.py +200 -0
  17. mapproxy/cache/geopackage.py +647 -0
  18. mapproxy/cache/legend.py +87 -0
  19. mapproxy/cache/mbtiles.py +411 -0
  20. mapproxy/cache/meta.py +80 -0
  21. mapproxy/cache/path.py +261 -0
  22. mapproxy/cache/redis.py +152 -0
  23. mapproxy/cache/renderd.py +100 -0
  24. mapproxy/cache/riak.py +206 -0
  25. mapproxy/cache/s3.py +209 -0
  26. mapproxy/cache/tile.py +736 -0
  27. mapproxy/client/__init__.py +0 -0
  28. mapproxy/client/arcgis.py +82 -0
  29. mapproxy/client/cgi.py +141 -0
  30. mapproxy/client/http.py +295 -0
  31. mapproxy/client/log.py +33 -0
  32. mapproxy/client/tile.py +158 -0
  33. mapproxy/client/wms.py +255 -0
  34. mapproxy/compat/__init__.py +0 -0
  35. mapproxy/compat/image.py +86 -0
  36. mapproxy/config/__init__.py +22 -0
  37. mapproxy/config/config-schema.json +813 -0
  38. mapproxy/config/config.py +213 -0
  39. mapproxy/config/coverage.py +108 -0
  40. mapproxy/config/defaults.py +102 -0
  41. mapproxy/config/loader.py +2399 -0
  42. mapproxy/config/spec.py +657 -0
  43. mapproxy/config/validator.py +242 -0
  44. mapproxy/config_template/__init__.py +0 -0
  45. mapproxy/config_template/base_config/config.wsgi +10 -0
  46. mapproxy/config_template/base_config/full_example.yaml +598 -0
  47. mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
  48. mapproxy/config_template/base_config/log.ini +35 -0
  49. mapproxy/config_template/base_config/mapproxy.yaml +60 -0
  50. mapproxy/config_template/base_config/seed.yaml +27 -0
  51. mapproxy/exception.py +149 -0
  52. mapproxy/featureinfo.py +251 -0
  53. mapproxy/grid.py +1199 -0
  54. mapproxy/image/__init__.py +549 -0
  55. mapproxy/image/fonts/DejaVuSans.ttf +0 -0
  56. mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
  57. mapproxy/image/fonts/LICENSE +99 -0
  58. mapproxy/image/fonts/__init__.py +0 -0
  59. mapproxy/image/mask.py +79 -0
  60. mapproxy/image/merge.py +323 -0
  61. mapproxy/image/message.py +357 -0
  62. mapproxy/image/opts.py +185 -0
  63. mapproxy/image/tile.py +171 -0
  64. mapproxy/image/transform.py +350 -0
  65. mapproxy/layer.py +489 -0
  66. mapproxy/multiapp.py +230 -0
  67. mapproxy/proj.py +309 -0
  68. mapproxy/request/__init__.py +18 -0
  69. mapproxy/request/arcgis.py +268 -0
  70. mapproxy/request/base.py +466 -0
  71. mapproxy/request/tile.py +131 -0
  72. mapproxy/request/wms/__init__.py +829 -0
  73. mapproxy/request/wms/exception.py +107 -0
  74. mapproxy/request/wmts.py +442 -0
  75. mapproxy/response.py +237 -0
  76. mapproxy/script/__init__.py +0 -0
  77. mapproxy/script/conf/__init__.py +0 -0
  78. mapproxy/script/conf/app.py +222 -0
  79. mapproxy/script/conf/caches.py +44 -0
  80. mapproxy/script/conf/geopackage.py +136 -0
  81. mapproxy/script/conf/layers.py +54 -0
  82. mapproxy/script/conf/seeds.py +36 -0
  83. mapproxy/script/conf/sources.py +88 -0
  84. mapproxy/script/conf/utils.py +148 -0
  85. mapproxy/script/defrag.py +187 -0
  86. mapproxy/script/export.py +337 -0
  87. mapproxy/script/grids.py +198 -0
  88. mapproxy/script/scales.py +134 -0
  89. mapproxy/script/util.py +410 -0
  90. mapproxy/script/wms_capabilities.py +160 -0
  91. mapproxy/seed/__init__.py +0 -0
  92. mapproxy/seed/cachelock.py +127 -0
  93. mapproxy/seed/cleanup.py +191 -0
  94. mapproxy/seed/config.py +481 -0
  95. mapproxy/seed/script.py +391 -0
  96. mapproxy/seed/seeder.py +551 -0
  97. mapproxy/seed/spec.py +66 -0
  98. mapproxy/seed/util.py +266 -0
  99. mapproxy/service/__init__.py +14 -0
  100. mapproxy/service/base.py +45 -0
  101. mapproxy/service/demo.py +364 -0
  102. mapproxy/service/kml.py +333 -0
  103. mapproxy/service/ows.py +39 -0
  104. mapproxy/service/template_helper.py +55 -0
  105. mapproxy/service/templates/demo/capabilities_demo.html +18 -0
  106. mapproxy/service/templates/demo/demo.html +181 -0
  107. mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
  108. mapproxy/service/templates/demo/static/img/blank.gif +0 -0
  109. mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
  110. mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
  111. mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
  112. mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
  113. mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
  114. mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
  115. mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
  116. mapproxy/service/templates/demo/static/logo.png +0 -0
  117. mapproxy/service/templates/demo/static/ol.css +345 -0
  118. mapproxy/service/templates/demo/static/ol.js +4 -0
  119. mapproxy/service/templates/demo/static/proj4.min.js +1 -0
  120. mapproxy/service/templates/demo/static/proj4defs.js +1 -0
  121. mapproxy/service/templates/demo/static/site.css +137 -0
  122. mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
  123. mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
  124. mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
  125. mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
  126. mapproxy/service/templates/demo/static.html +34 -0
  127. mapproxy/service/templates/demo/tms_demo.html +117 -0
  128. mapproxy/service/templates/demo/wms_demo.html +144 -0
  129. mapproxy/service/templates/demo/wmts_demo.html +118 -0
  130. mapproxy/service/templates/tms_capabilities.xml +13 -0
  131. mapproxy/service/templates/tms_exception.xml +4 -0
  132. mapproxy/service/templates/tms_root_resource.xml +7 -0
  133. mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
  134. mapproxy/service/templates/wms100capabilities.xml +112 -0
  135. mapproxy/service/templates/wms100exception.xml +4 -0
  136. mapproxy/service/templates/wms110capabilities.xml +152 -0
  137. mapproxy/service/templates/wms110exception.xml +5 -0
  138. mapproxy/service/templates/wms111capabilities.xml +183 -0
  139. mapproxy/service/templates/wms111exception.xml +5 -0
  140. mapproxy/service/templates/wms130capabilities.xml +326 -0
  141. mapproxy/service/templates/wms130exception.xml +8 -0
  142. mapproxy/service/templates/wmts100capabilities.xml +155 -0
  143. mapproxy/service/templates/wmts100exception.xml +9 -0
  144. mapproxy/service/tile.py +540 -0
  145. mapproxy/service/wms.py +868 -0
  146. mapproxy/service/wmts.py +387 -0
  147. mapproxy/source/__init__.py +83 -0
  148. mapproxy/source/arcgis.py +39 -0
  149. mapproxy/source/error.py +40 -0
  150. mapproxy/source/mapnik.py +262 -0
  151. mapproxy/source/tile.py +97 -0
  152. mapproxy/source/wms.py +273 -0
  153. mapproxy/srs.py +734 -0
  154. mapproxy/template.py +54 -0
  155. mapproxy/test/__init__.py +0 -0
  156. mapproxy/test/conftest.py +8 -0
  157. mapproxy/test/helper.py +255 -0
  158. mapproxy/test/http.py +511 -0
  159. mapproxy/test/image.py +219 -0
  160. mapproxy/test/mocker.py +2291 -0
  161. mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
  162. mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
  163. mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
  164. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
  165. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
  166. mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
  167. mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
  168. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
  169. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
  170. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
  171. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
  172. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
  173. mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
  174. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
  175. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
  176. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
  177. mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
  178. mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
  179. mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
  180. mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
  181. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
  182. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
  183. mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
  184. mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
  185. mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
  186. mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
  187. mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
  188. mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
  189. mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
  190. mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
  191. mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
  192. mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
  193. mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
  194. mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
  195. mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
  196. mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
  197. mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
  198. mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
  199. mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
  200. mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
  201. mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
  202. mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
  203. mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
  204. mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
  205. mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
  206. mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
  207. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
  208. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
  209. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
  210. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
  211. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
  212. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
  213. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
  214. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
  215. mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
  216. mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  217. mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
  218. mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  219. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
  220. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
  221. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
  222. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
  223. mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
  224. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
  225. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
  226. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
  227. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
  228. mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
  229. mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  230. mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
  231. mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  232. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
  233. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
  234. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
  235. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
  236. mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
  237. mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
  238. mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
  239. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
  240. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
  241. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
  242. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
  243. mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
  244. mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
  245. mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
  246. mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
  247. mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
  248. mapproxy/test/schemas/xml.xsd +287 -0
  249. mapproxy/test/system/__init__.py +98 -0
  250. mapproxy/test/system/fixture/arcgis.yaml +57 -0
  251. mapproxy/test/system/fixture/auth.yaml +70 -0
  252. mapproxy/test/system/fixture/cache.mbtiles +0 -0
  253. mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
  254. mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
  255. mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
  256. mapproxy/test/system/fixture/cache_coverage.yaml +84 -0
  257. mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
  258. mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
  259. mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
  260. mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
  261. mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
  262. mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
  263. mapproxy/test/system/fixture/cache_s3.yaml +58 -0
  264. mapproxy/test/system/fixture/cache_source.yaml +81 -0
  265. mapproxy/test/system/fixture/combined_sources.yaml +130 -0
  266. mapproxy/test/system/fixture/coverage.yaml +77 -0
  267. mapproxy/test/system/fixture/demo.yaml +135 -0
  268. mapproxy/test/system/fixture/dimension.yaml +59 -0
  269. mapproxy/test/system/fixture/disable_storage.yaml +25 -0
  270. mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
  271. mapproxy/test/system/fixture/formats.yaml +72 -0
  272. mapproxy/test/system/fixture/inspire.yaml +101 -0
  273. mapproxy/test/system/fixture/inspire_full.yaml +124 -0
  274. mapproxy/test/system/fixture/kml_layer.yaml +66 -0
  275. mapproxy/test/system/fixture/layer.yaml +260 -0
  276. mapproxy/test/system/fixture/layergroups.yaml +57 -0
  277. mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
  278. mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
  279. mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
  280. mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
  281. mapproxy/test/system/fixture/mapserver.yaml +23 -0
  282. mapproxy/test/system/fixture/minimal_cgi.py +16 -0
  283. mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
  284. mapproxy/test/system/fixture/multi_cache_layers.yaml +111 -0
  285. mapproxy/test/system/fixture/multiapp1.yaml +20 -0
  286. mapproxy/test/system/fixture/multiapp2.yaml +19 -0
  287. mapproxy/test/system/fixture/renderd_client.yaml +55 -0
  288. mapproxy/test/system/fixture/scalehints.yaml +70 -0
  289. mapproxy/test/system/fixture/seed.yaml +94 -0
  290. mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
  291. mapproxy/test/system/fixture/seed_old.yaml +12 -0
  292. mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
  293. mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
  294. mapproxy/test/system/fixture/seedonly.yaml +51 -0
  295. mapproxy/test/system/fixture/sld.yaml +35 -0
  296. mapproxy/test/system/fixture/source_errors.yaml +84 -0
  297. mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
  298. mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
  299. mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
  300. mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
  301. mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
  302. mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
  303. mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
  304. mapproxy/test/system/fixture/util_grids.yaml +29 -0
  305. mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
  306. mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
  307. mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
  308. mapproxy/test/system/fixture/watermark.yaml +50 -0
  309. mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
  310. mapproxy/test/system/fixture/wms_versions.yaml +38 -0
  311. mapproxy/test/system/fixture/wmts.yaml +134 -0
  312. mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
  313. mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
  314. mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
  315. mapproxy/test/system/test_arcgis.py +156 -0
  316. mapproxy/test/system/test_auth.py +1133 -0
  317. mapproxy/test/system/test_behind_proxy.py +75 -0
  318. mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
  319. mapproxy/test/system/test_cache_azureblob.py +127 -0
  320. mapproxy/test/system/test_cache_band_merge.py +103 -0
  321. mapproxy/test/system/test_cache_coverage.py +168 -0
  322. mapproxy/test/system/test_cache_geopackage.py +144 -0
  323. mapproxy/test/system/test_cache_grid_names.py +89 -0
  324. mapproxy/test/system/test_cache_mbtiles.py +85 -0
  325. mapproxy/test/system/test_cache_s3.py +115 -0
  326. mapproxy/test/system/test_cache_source.py +146 -0
  327. mapproxy/test/system/test_combined_sources.py +335 -0
  328. mapproxy/test/system/test_coverage.py +140 -0
  329. mapproxy/test/system/test_decorate_img.py +214 -0
  330. mapproxy/test/system/test_demo.py +56 -0
  331. mapproxy/test/system/test_demo_with_extra_service.py +57 -0
  332. mapproxy/test/system/test_dimensions.py +279 -0
  333. mapproxy/test/system/test_disable_storage.py +42 -0
  334. mapproxy/test/system/test_formats.py +219 -0
  335. mapproxy/test/system/test_inspire_vs.py +173 -0
  336. mapproxy/test/system/test_kml.py +264 -0
  337. mapproxy/test/system/test_layergroups.py +160 -0
  338. mapproxy/test/system/test_legendgraphic.py +308 -0
  339. mapproxy/test/system/test_mapnik.py +162 -0
  340. mapproxy/test/system/test_mapserver.py +83 -0
  341. mapproxy/test/system/test_mixed_mode_format.py +201 -0
  342. mapproxy/test/system/test_multi_cache_layers.py +169 -0
  343. mapproxy/test/system/test_multiapp.py +92 -0
  344. mapproxy/test/system/test_refresh.py +206 -0
  345. mapproxy/test/system/test_renderd_client.py +304 -0
  346. mapproxy/test/system/test_response_headers.py +54 -0
  347. mapproxy/test/system/test_scalehints.py +140 -0
  348. mapproxy/test/system/test_seed.py +425 -0
  349. mapproxy/test/system/test_seed_only.py +93 -0
  350. mapproxy/test/system/test_sld.py +120 -0
  351. mapproxy/test/system/test_source_errors.py +377 -0
  352. mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
  353. mapproxy/test/system/test_tms.py +277 -0
  354. mapproxy/test/system/test_tms_origin.py +46 -0
  355. mapproxy/test/system/test_util_conf.py +434 -0
  356. mapproxy/test/system/test_util_export.py +210 -0
  357. mapproxy/test/system/test_util_grids.py +88 -0
  358. mapproxy/test/system/test_util_wms_capabilities.py +182 -0
  359. mapproxy/test/system/test_watermark.py +91 -0
  360. mapproxy/test/system/test_wms.py +1616 -0
  361. mapproxy/test/system/test_wms_srs_extent.py +165 -0
  362. mapproxy/test/system/test_wms_version.py +85 -0
  363. mapproxy/test/system/test_wmsc.py +116 -0
  364. mapproxy/test/system/test_wmts.py +334 -0
  365. mapproxy/test/system/test_wmts_dimensions.py +206 -0
  366. mapproxy/test/system/test_wmts_restful.py +198 -0
  367. mapproxy/test/system/test_xslt_featureinfo.py +423 -0
  368. mapproxy/test/test_http_helper.py +217 -0
  369. mapproxy/test/unit/__init__.py +0 -0
  370. mapproxy/test/unit/epsg +2 -0
  371. mapproxy/test/unit/polygons/polygons.dbf +0 -0
  372. mapproxy/test/unit/polygons/polygons.shp +0 -0
  373. mapproxy/test/unit/polygons/polygons.shx +0 -0
  374. mapproxy/test/unit/test_async.py +242 -0
  375. mapproxy/test/unit/test_auth.py +430 -0
  376. mapproxy/test/unit/test_cache.py +1356 -0
  377. mapproxy/test/unit/test_cache_azureblob.py +97 -0
  378. mapproxy/test/unit/test_cache_compact.py +324 -0
  379. mapproxy/test/unit/test_cache_couchdb.py +118 -0
  380. mapproxy/test/unit/test_cache_geopackage.py +256 -0
  381. mapproxy/test/unit/test_cache_redis.py +123 -0
  382. mapproxy/test/unit/test_cache_riak.py +80 -0
  383. mapproxy/test/unit/test_cache_s3.py +93 -0
  384. mapproxy/test/unit/test_cache_tile.py +477 -0
  385. mapproxy/test/unit/test_client.py +488 -0
  386. mapproxy/test/unit/test_client_arcgis.py +74 -0
  387. mapproxy/test/unit/test_client_cgi.py +140 -0
  388. mapproxy/test/unit/test_collections.py +116 -0
  389. mapproxy/test/unit/test_concat_legends.py +37 -0
  390. mapproxy/test/unit/test_conf_loader.py +1267 -0
  391. mapproxy/test/unit/test_conf_validator.py +427 -0
  392. mapproxy/test/unit/test_config.py +118 -0
  393. mapproxy/test/unit/test_decorate_img.py +185 -0
  394. mapproxy/test/unit/test_exceptions.py +270 -0
  395. mapproxy/test/unit/test_featureinfo.py +313 -0
  396. mapproxy/test/unit/test_file_lock_load.py +49 -0
  397. mapproxy/test/unit/test_geom.py +512 -0
  398. mapproxy/test/unit/test_grid.py +1279 -0
  399. mapproxy/test/unit/test_image.py +1051 -0
  400. mapproxy/test/unit/test_image_mask.py +181 -0
  401. mapproxy/test/unit/test_image_messages.py +209 -0
  402. mapproxy/test/unit/test_image_options.py +160 -0
  403. mapproxy/test/unit/test_isodate.py +118 -0
  404. mapproxy/test/unit/test_multiapp.py +163 -0
  405. mapproxy/test/unit/test_ogr_reader.py +51 -0
  406. mapproxy/test/unit/test_request.py +745 -0
  407. mapproxy/test/unit/test_request_wmts.py +178 -0
  408. mapproxy/test/unit/test_response.py +78 -0
  409. mapproxy/test/unit/test_seed.py +365 -0
  410. mapproxy/test/unit/test_seed_cachelock.py +91 -0
  411. mapproxy/test/unit/test_srs.py +215 -0
  412. mapproxy/test/unit/test_tiled_source.py +122 -0
  413. mapproxy/test/unit/test_tilefilter.py +31 -0
  414. mapproxy/test/unit/test_times.py +25 -0
  415. mapproxy/test/unit/test_timeutils.py +50 -0
  416. mapproxy/test/unit/test_util_conf_utils.py +75 -0
  417. mapproxy/test/unit/test_utils.py +476 -0
  418. mapproxy/test/unit/test_wms_capabilities.py +44 -0
  419. mapproxy/test/unit/test_wms_layer.py +113 -0
  420. mapproxy/test/unit/test_yaml.py +68 -0
  421. mapproxy/tilefilter.py +61 -0
  422. mapproxy/util/__init__.py +0 -0
  423. mapproxy/util/async_.py +229 -0
  424. mapproxy/util/collections.py +134 -0
  425. mapproxy/util/coverage.py +337 -0
  426. mapproxy/util/ext/__init__.py +14 -0
  427. mapproxy/util/ext/dictspec/__init__.py +1 -0
  428. mapproxy/util/ext/dictspec/spec.py +131 -0
  429. mapproxy/util/ext/dictspec/test/__init__.py +0 -0
  430. mapproxy/util/ext/dictspec/test/test_validator.py +278 -0
  431. mapproxy/util/ext/dictspec/validator.py +194 -0
  432. mapproxy/util/ext/local.py +198 -0
  433. mapproxy/util/ext/lockfile.py +140 -0
  434. mapproxy/util/ext/odict.py +321 -0
  435. mapproxy/util/ext/serving.py +491 -0
  436. mapproxy/util/ext/tempita/__init__.py +1093 -0
  437. mapproxy/util/ext/tempita/_looper.py +163 -0
  438. mapproxy/util/ext/tempita/string_utils.py +24 -0
  439. mapproxy/util/ext/wmsparse/__init__.py +3 -0
  440. mapproxy/util/ext/wmsparse/duration.py +600 -0
  441. mapproxy/util/ext/wmsparse/parse.py +307 -0
  442. mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
  443. mapproxy/util/ext/wmsparse/test/test_parse.py +111 -0
  444. mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
  445. mapproxy/util/ext/wmsparse/test/wms-example-111.xml +90 -0
  446. mapproxy/util/ext/wmsparse/test/wms-example-130.xml +120 -0
  447. mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
  448. mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
  449. mapproxy/util/ext/wmsparse/util.py +189 -0
  450. mapproxy/util/fs.py +164 -0
  451. mapproxy/util/geom.py +307 -0
  452. mapproxy/util/lib.py +117 -0
  453. mapproxy/util/lock.py +171 -0
  454. mapproxy/util/ogr.py +247 -0
  455. mapproxy/util/py.py +75 -0
  456. mapproxy/util/times.py +78 -0
  457. mapproxy/util/yaml.py +58 -0
  458. mapproxy/version.py +33 -0
  459. mapproxy/wsgiapp.py +167 -0
File without changes
@@ -0,0 +1,82 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2010 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from mapproxy.client.http import HTTPClient
17
+ from mapproxy.client.wms import WMSInfoClient
18
+ from mapproxy.srs import SRS
19
+ from mapproxy.featureinfo import create_featureinfo_doc
20
+
21
+
22
+ class ArcGISClient(object):
23
+ def __init__(self, request_template, http_client=None):
24
+ self.request_template = request_template
25
+ self.http_client = http_client
26
+
27
+ def retrieve(self, query, format):
28
+ url = self._query_url(query, format)
29
+ resp = self.http_client.open(url)
30
+ return resp
31
+
32
+ def _query_url(self, query, format):
33
+ req = self.request_template.copy()
34
+ req.params.format = format
35
+ req.params.bbox = query.bbox
36
+ req.params.size = query.size
37
+ req.params.bboxSR = query.srs
38
+ req.params.imageSR = query.srs
39
+ req.params.transparent = query.transparent
40
+
41
+ return req.complete_url
42
+
43
+ def combined_client(self, other, query):
44
+ return
45
+
46
+
47
+ class ArcGISInfoClient(WMSInfoClient):
48
+ def __init__(self, request_template, supported_srs=None, http_client=None,
49
+ return_geometries=False,
50
+ tolerance=5,
51
+ ):
52
+ self.request_template = request_template
53
+ self.http_client = http_client or HTTPClient()
54
+ if not supported_srs and self.request_template.params.srs is not None:
55
+ supported_srs = [SRS(self.request_template.params.srs)]
56
+ self.supported_srs = supported_srs or []
57
+ self.return_geometries = return_geometries
58
+ self.tolerance = tolerance
59
+
60
+ def get_info(self, query):
61
+ if self.supported_srs and query.srs not in self.supported_srs:
62
+ query = self._get_transformed_query(query)
63
+ resp = self._retrieve(query)
64
+ # always use query.info_format and not content-type from response (even esri example server aleays return
65
+ # text/plain)
66
+ return create_featureinfo_doc(resp.read(), query.info_format)
67
+
68
+ def _query_url(self, query):
69
+ req = self.request_template.copy()
70
+ req.params.bbox = query.bbox
71
+ req.params.size = query.size
72
+ req.params.pos = query.pos
73
+ req.params.srs = query.srs.srs_code
74
+ if query.info_format.startswith('text/html'):
75
+ req.params['f'] = 'html'
76
+ else:
77
+ req.params['f'] = 'json'
78
+
79
+ req.params['tolerance'] = self.tolerance
80
+ req.params['returnGeometry'] = str(self.return_geometries).lower()
81
+
82
+ return req.complete_url
mapproxy/client/cgi.py ADDED
@@ -0,0 +1,141 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2011 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """
17
+ HTTP client that directly calls CGI executable.
18
+ """
19
+
20
+ import errno
21
+ import os
22
+ import re
23
+ import subprocess
24
+ import time
25
+ from io import BytesIO
26
+ from urllib.parse import urlparse
27
+
28
+ from mapproxy.source import SourceError
29
+ from mapproxy.image import ImageSource
30
+ from mapproxy.client.http import HTTPClientError
31
+ from mapproxy.client.log import log_request
32
+
33
+
34
+ def split_cgi_response(data):
35
+ headers = []
36
+ prev_n = 0
37
+ while True:
38
+ next_n = data.find(b'\n', prev_n)
39
+ if next_n < 0:
40
+ break
41
+ next_line_begin = data[next_n+1:next_n+3]
42
+ headers.append(data[prev_n:next_n].rstrip(b'\r'))
43
+ if next_line_begin[0:1] == b'\n':
44
+ return headers_dict(headers), data[next_n+2:]
45
+ elif next_line_begin == b'\r\n':
46
+ return headers_dict(headers), data[next_n+3:]
47
+ prev_n = next_n+1
48
+ return {}, data
49
+
50
+
51
+ def headers_dict(header_lines):
52
+ headers = {}
53
+ for line in header_lines:
54
+ if b':' in line:
55
+ key, value = line.split(b':', 1)
56
+ value = value.strip()
57
+ else:
58
+ key = line
59
+ value = None
60
+ key = key.decode('latin-1')
61
+ key = key[0].upper() + key[1:].lower()
62
+ if value:
63
+ value = value.decode('latin-1')
64
+ headers[key] = value
65
+ return headers
66
+
67
+
68
+ class IOwithHeaders(object):
69
+ def __init__(self, io, headers):
70
+ self.io = io
71
+ self.headers = headers
72
+
73
+ def __getattr__(self, name):
74
+ return getattr(self.io, name)
75
+
76
+
77
+ class CGIClient(object):
78
+ def __init__(self, script, no_headers=False, working_directory=None):
79
+ self.script = script
80
+ self.working_directory = working_directory
81
+ self.no_headers = no_headers
82
+
83
+ def open(self, url, data=None):
84
+ assert data is None, 'POST requests not supported by CGIClient'
85
+
86
+ parsed_url = urlparse(url)
87
+ environ = os.environ.copy()
88
+ environ.update({
89
+ 'QUERY_STRING': parsed_url.query,
90
+ 'REQUEST_METHOD': 'GET',
91
+ 'GATEWAY_INTERFACE': 'CGI/1.1',
92
+ 'SERVER_ADDR': '127.0.0.1',
93
+ 'SERVER_NAME': 'localhost',
94
+ 'SERVER_PROTOCOL': 'HTTP/1.0',
95
+ 'SERVER_SOFTWARE': 'MapProxy',
96
+ })
97
+
98
+ start_time = time.time()
99
+ try:
100
+ p = subprocess.Popen([self.script], env=environ,
101
+ stdout=subprocess.PIPE,
102
+ cwd=self.working_directory or os.path.dirname(self.script)
103
+ )
104
+ except OSError as ex:
105
+ if ex.errno == errno.ENOENT:
106
+ raise SourceError('CGI script not found (%s)' % (self.script,))
107
+ elif ex.errno == errno.EACCES:
108
+ raise SourceError('No permission for CGI script (%s)' % (self.script,))
109
+ else:
110
+ raise
111
+
112
+ stdout = p.communicate()[0]
113
+ ret = p.wait()
114
+ if ret != 0:
115
+ raise HTTPClientError('Error during CGI call (exit code: %d)'
116
+ % (ret, ))
117
+
118
+ if self.no_headers:
119
+ content = stdout
120
+ headers = dict()
121
+ else:
122
+ headers, content = split_cgi_response(stdout)
123
+
124
+ status_match = re.match(r'(\d\d\d) ', headers.get('Status', ''))
125
+ if status_match:
126
+ status_code = status_match.group(1)
127
+ else:
128
+ status_code = '-'
129
+ size = len(content)
130
+ content = IOwithHeaders(BytesIO(content), headers)
131
+
132
+ log_request('%s:%s' % (self.script, parsed_url.query),
133
+ status_code, size=size, method='CGI', duration=time.time()-start_time)
134
+ return content
135
+
136
+ def open_image(self, url, data=None):
137
+ resp = self.open(url, data=data)
138
+ if 'Content-type' in resp.headers:
139
+ if not resp.headers['Content-type'].lower().startswith('image'):
140
+ raise HTTPClientError('response is not an image: (%s)' % (resp.read()))
141
+ return ImageSource(resp)
@@ -0,0 +1,295 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2010-2017 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """
17
+ Tile retrieval (WMS, TMS, etc.).
18
+ """
19
+ import sys
20
+ import time
21
+
22
+ from mapproxy.version import version
23
+ from mapproxy.image import ImageSource
24
+ from mapproxy.util.py import reraise_exception
25
+ from mapproxy.client.log import log_request
26
+
27
+ from urllib import request as urllib2
28
+ from urllib.error import URLError, HTTPError
29
+ from urllib.request import HTTPCookieProcessor
30
+ from http import client as httplib
31
+ from http.cookiejar import CookieJar
32
+
33
+ import socket
34
+ import ssl
35
+
36
+
37
+ class HTTPClientError(Exception):
38
+ def __init__(self, arg, response_code=None, full_msg=None):
39
+ Exception.__init__(self, arg)
40
+ self.response_code = response_code
41
+ self.full_msg = full_msg
42
+
43
+
44
+ def build_https_handler(ssl_ca_certs, insecure):
45
+ if insecure:
46
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
47
+ ctx.check_hostname = False
48
+ ctx.verify_mode = ssl.CERT_NONE
49
+ elif ssl_ca_certs:
50
+ ctx = ssl.create_default_context(cafile=ssl_ca_certs)
51
+ else:
52
+ ctx = ssl.create_default_context()
53
+ return urllib2.HTTPSHandler(context=ctx)
54
+
55
+
56
+ class VerifiedHTTPSConnection(httplib.HTTPSConnection):
57
+ def __init__(self, *args, **kw):
58
+ self._ca_certs = kw.pop('ca_certs', None)
59
+ httplib.HTTPSConnection.__init__(self, *args, **kw)
60
+
61
+ def connect(self):
62
+ # overrides the version in httplib so that we do
63
+ # certificate verification
64
+
65
+ if hasattr(socket, 'create_connection') and hasattr(self, 'source_address'):
66
+ sock = socket.create_connection((self.host, self.port),
67
+ self.timeout, self.source_address)
68
+ else:
69
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
70
+ sock.connect((self.host, self.port))
71
+
72
+ if hasattr(self, '_tunnel_host') and self._tunnel_host:
73
+ # for Python >= 2.6 with proxy support
74
+ self.sock = sock
75
+ self._tunnel()
76
+
77
+ # wrap the socket using verification with the root
78
+ # certs in self.ca_certs_path
79
+ self.sock = ssl.wrap_socket(sock,
80
+ self.key_file,
81
+ self.cert_file,
82
+ cert_reqs=ssl.CERT_REQUIRED,
83
+ ca_certs=self._ca_certs)
84
+
85
+
86
+ def verified_https_connection_with_ca_certs(ca_certs):
87
+ """
88
+ Creates VerifiedHTTPSConnection classes with given ca_certs file.
89
+ """
90
+ def wrapper(*args, **kw):
91
+ kw['ca_certs'] = ca_certs
92
+ return VerifiedHTTPSConnection(*args, **kw)
93
+ return wrapper
94
+
95
+
96
+ class VerifiedHTTPSHandler(urllib2.HTTPSHandler):
97
+ def __init__(self, connection_class=VerifiedHTTPSConnection):
98
+ self.specialized_conn_class = connection_class
99
+ urllib2.HTTPSHandler.__init__(self)
100
+
101
+ def https_open(self, req):
102
+ return self.do_open(self.specialized_conn_class, req)
103
+
104
+
105
+ class _URLOpenerCache(object):
106
+ """
107
+ Creates custom URLOpener with BasicAuth and HTTPS handler.
108
+
109
+ Caches and reuses opener if possible (i.e. if they share the same
110
+ ssl_ca_certs).
111
+ """
112
+
113
+ def __init__(self):
114
+ self._opener = {}
115
+
116
+ def __call__(self, ssl_ca_certs, url, username, password, insecure=False, manage_cookies=False):
117
+ cache_key = (ssl_ca_certs, insecure, manage_cookies)
118
+ if cache_key not in self._opener:
119
+ handlers = []
120
+ https_handler = build_https_handler(ssl_ca_certs, insecure)
121
+ if https_handler:
122
+ handlers.append(https_handler)
123
+ passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
124
+ authhandler = urllib2.HTTPBasicAuthHandler(passman)
125
+ handlers.append(authhandler)
126
+ authhandler = urllib2.HTTPDigestAuthHandler(passman)
127
+ handlers.append(authhandler)
128
+ if manage_cookies:
129
+ cj = CookieJar()
130
+ handlers.append(HTTPCookieProcessor(cj))
131
+
132
+ opener = urllib2.build_opener(*handlers)
133
+
134
+ opener.addheaders = [('User-agent', 'MapProxy-%s' % (version,))]
135
+
136
+ self._opener[cache_key] = (opener, passman)
137
+ else:
138
+ opener, passman = self._opener[cache_key]
139
+
140
+ if url is not None and username is not None and password is not None:
141
+ passman.add_password(None, url, username, password)
142
+
143
+ return opener
144
+
145
+
146
+ create_url_opener = _URLOpenerCache()
147
+
148
+
149
+ class HTTPClient(object):
150
+ def __init__(self, url=None, username=None, password=None, insecure=False,
151
+ ssl_ca_certs=None, timeout=None, headers=None, hide_error_details=False,
152
+ manage_cookies=False):
153
+ self._timeout = timeout
154
+ if url and url.startswith('https'):
155
+ if insecure:
156
+ ssl_ca_certs = None
157
+
158
+ self.opener = create_url_opener(ssl_ca_certs, url, username, password,
159
+ insecure=insecure, manage_cookies=manage_cookies)
160
+ self.header_list = headers.items() if headers else []
161
+ self.hide_error_details = hide_error_details
162
+
163
+ def open(self, url, data=None, method=None):
164
+ code = None
165
+ result = None
166
+ try:
167
+ req = urllib2.Request(url, data=data)
168
+ except ValueError as e:
169
+ err = self.handle_url_exception(url, 'URL not correct', e.args[0])
170
+ reraise_exception(err, sys.exc_info())
171
+ for key, value in self.header_list:
172
+ req.add_header(key, value)
173
+ if method:
174
+ req.method = method
175
+ try:
176
+ start_time = time.time()
177
+ if self._timeout is not None:
178
+ result = self.opener.open(req, timeout=self._timeout)
179
+ else:
180
+ result = self.opener.open(req)
181
+ except HTTPError as e:
182
+ code = e.code
183
+ err = self.handle_url_exception(url, 'HTTP Error', str(code), response_code=code)
184
+ reraise_exception(err, sys.exc_info())
185
+ except URLError as e:
186
+ if isinstance(e.reason, ssl.SSLError):
187
+ err = self.handle_url_exception(url, 'Could not verify connection to URL', e.reason.args[1])
188
+ reraise_exception(err, sys.exc_info())
189
+ try:
190
+ reason = e.reason.args[1]
191
+ except (AttributeError, IndexError):
192
+ reason = e.reason
193
+ err = self.handle_url_exception(url, 'No response from URL', reason)
194
+ reraise_exception(err, sys.exc_info())
195
+ except ValueError as e:
196
+ err = self.handle_url_exception(url, 'URL not correct', e.args[0])
197
+ reraise_exception(err, sys.exc_info())
198
+ except Exception as e:
199
+ err = self.handle_url_exception(url, 'Internal HTTP error', repr(e))
200
+ reraise_exception(err, sys.exc_info())
201
+ else:
202
+ code = getattr(result, 'code', 200)
203
+ if code == 204:
204
+ raise HTTPClientError('HTTP Error "204 No Content"', response_code=204)
205
+ return result
206
+ finally:
207
+ log_request(url, code, result, duration=time.time()-start_time, method=req.get_method())
208
+
209
+ def open_image(self, url, data=None):
210
+ resp = self.open(url, data=data)
211
+ if 'content-type' in resp.headers:
212
+ if not resp.headers['content-type'].lower().startswith('image'):
213
+ raise HTTPClientError('response is not an image: (%s)' % (resp.read()))
214
+ return ImageSource(resp)
215
+
216
+ def handle_url_exception(self, url, message, reason, response_code=None):
217
+ full_msg = '%s "%s": %s' % (message, url, reason)
218
+ if self.hide_error_details:
219
+ return HTTPClientError(
220
+ '{} (see logs for URL and reason).'.format(message),
221
+ response_code=response_code,
222
+ full_msg=full_msg,
223
+ )
224
+ else:
225
+ return HTTPClientError(
226
+ full_msg,
227
+ response_code=response_code,
228
+ )
229
+
230
+
231
+ def auth_data_from_url(url):
232
+ """
233
+ >>> auth_data_from_url('invalid_url')
234
+ ('invalid_url', (None, None))
235
+ >>> auth_data_from_url('http://localhost/bar')
236
+ ('http://localhost/bar', (None, None))
237
+ >>> auth_data_from_url('http://bar@localhost/bar')
238
+ ('http://localhost/bar', ('bar', None))
239
+ >>> auth_data_from_url('http://bar:baz@localhost/bar')
240
+ ('http://localhost/bar', ('bar', 'baz'))
241
+ >>> auth_data_from_url('http://bar:b:az@@localhost/bar')
242
+ ('http://localhost/bar', ('bar', 'b:az@'))
243
+ >>> auth_data_from_url('http://bar foo; foo@bar:b:az@@localhost/bar')
244
+ ('http://localhost/bar', ('bar foo; foo@bar', 'b:az@'))
245
+ >>> auth_data_from_url('https://bar:foo#;%$@localhost/bar')
246
+ ('https://localhost/bar', ('bar', 'foo#;%$'))
247
+ >>> auth_data_from_url('http://localhost/bar@2x')
248
+ ('http://localhost/bar@2x', (None, None))
249
+ >>> auth_data_from_url('http://bar@localhost/bar@2x')
250
+ ('http://localhost/bar@2x', ('bar', None))
251
+ >>> auth_data_from_url('http://bar:baz@localhost/bar@2x')
252
+ ('http://localhost/bar@2x', ('bar', 'baz'))
253
+ >>> auth_data_from_url('https://bar@localhost/bar/0/0/0@2x.png')
254
+ ('https://localhost/bar/0/0/0@2x.png', ('bar', None))
255
+ >>> auth_data_from_url('http://bar:baz@localhost/bar@2x.png')
256
+ ('http://localhost/bar@2x.png', ('bar', 'baz'))
257
+ """
258
+ if not url or '://' not in url:
259
+ # be silent for invalid URLs
260
+ return url, (None, None)
261
+
262
+ schema, url = url.split('://', 1)
263
+ if '/' in url:
264
+ host, request = url.split('/', 1)
265
+ else:
266
+ host, request = url, ''
267
+
268
+ username = password = None
269
+ if '@' in host:
270
+ auth_data, host = host.rsplit('@', 1)
271
+ if ':' in auth_data:
272
+ username, password = auth_data.split(':', 1)
273
+ else:
274
+ username = auth_data
275
+ url = schema + "://" + host + "/" + request
276
+ return url, (username, password)
277
+
278
+
279
+ def open_url(url):
280
+ url, (username, password) = auth_data_from_url(url)
281
+ http_client = HTTPClient(url, username, password)
282
+ return http_client.open(url)
283
+
284
+
285
+ def retrieve_image(url, client=None):
286
+ """
287
+ Retrive an image from `url`.
288
+
289
+ :return: the image as a file object (with url .header and .info)
290
+ :raise HTTPClientError: if response content-type doesn't start with image
291
+ """
292
+ resp = open_url(url)
293
+ if not resp.headers['content-type'].startswith('image'):
294
+ raise HTTPClientError('response is not an image: (%s)' % (resp.read()))
295
+ return ImageSource(resp)
mapproxy/client/log.py ADDED
@@ -0,0 +1,33 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2011 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import logging
17
+ logger = logging.getLogger('mapproxy.source.request')
18
+
19
+
20
+ def log_request(url, status, result=None, size=None, method='GET', duration=None):
21
+ if not logger.isEnabledFor(logging.INFO):
22
+ return
23
+
24
+ if not size and result is not None:
25
+ size = result.headers.get('Content-length')
26
+ if size:
27
+ size = '%.1f' % (int(size)/1024.0, )
28
+ else:
29
+ size = '-'
30
+ if not status:
31
+ status = '-'
32
+ duration = '%d' % (duration*1000) if duration else '-'
33
+ logger.info('%s %s %s %s %s', method, url.replace(' ', ''), status, size, duration)