cgi.ml 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. (*
  2. * cgi.ml
  3. *
  4. * Created by Marcus Rohrmoser on 16.05.20.
  5. * Copyright © 2020-2021 Marcus Rohrmoser mobile Software http://mro.name/~me. All rights reserved.
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *)
  20. let globe = "🌐"
  21. open Lib
  22. open Lib.Cgi
  23. let handle_hash oc req =
  24. match req.path_info |> String.split_on_char '/' with
  25. | [ ""; hash ] -> (
  26. match Geohash.decode hash with
  27. | Error _ -> error oc 406 "Cannot decode hash."
  28. | Ok ((lat, lon), (dlat, dlon)) ->
  29. let mime = "text/xml"
  30. and xslt = "gpx2html.xslt"
  31. and uri = req |> request_uri
  32. and base = "http://purl.mro.name/geohash" in
  33. Printf.fprintf oc "%s: %s\n" "Content-Type" mime;
  34. Printf.fprintf oc "\n";
  35. Printf.fprintf oc
  36. "<?xml version='1.0'?><!-- \
  37. https://www.topografix.com/GPX/1/1/gpx.xsd -->\n\
  38. <?xml-stylesheet type='text/xsl' href='%s'?>\n\
  39. <gpx xmlns='http://www.topografix.com/GPX/1/1' version='1.1' \
  40. creator='%s'>\n\
  41. \ <metadata>\n\
  42. \ <link href='%s://%s:%s%s'/>\n\
  43. \ <bounds minlat='%f' minlon='%f' maxlat='%f' maxlon='%f'/>\n\
  44. \ </metadata>\n\
  45. \ <wpt lat='%f' lon='%f'>\n\
  46. \ <name>#%s</name>\n\
  47. \ <link href='%s://%s:%s%s'/>\n\
  48. \ </wpt>\n\
  49. </gpx>"
  50. xslt base req.scheme req.host req.server_port uri (lat -. dlat)
  51. (lon -. dlon) (lat +. dlat) (lon +. dlon) lat lon hash req.scheme
  52. req.host req.server_port uri;
  53. 0)
  54. | _ -> error oc 404 "Not found"
  55. let handle oc req =
  56. let mercator_birth = "u154c" and uri = req |> request_uri in
  57. match req.request_method with
  58. | "GET" -> (
  59. let r n = n |> Res.read |> Option.value ~default:"" in
  60. match req.path_info with
  61. | "/about" -> dump_clob oc "text/xml" (r "doap.rdf")
  62. | "/LICENSE" -> dump_clob oc "text/plain" (r "LICENSE")
  63. | "/doap2html.xslt" -> dump_clob oc "text/xml" (r "doap2html.xslt")
  64. | "/gpx2html.xslt" -> dump_clob oc "text/xml" (r "gpx2html.xslt")
  65. | "" -> uri ^ "/" |> redirect oc
  66. | "/" -> (
  67. match req.query_string with
  68. | "" -> uri ^ mercator_birth |> redirect oc
  69. | qs -> (
  70. match qs |> Route.coord_from_qs with
  71. | Error (`NoMatch (_, s')) ->
  72. error oc 406 ("Cannot encode coords: '" ^ s' ^ "'")
  73. | Error (`ConverterFailure _) ->
  74. error oc 406 "Cannot encode coords."
  75. | Ok co -> (
  76. (* actually logic :-( *)
  77. let prec =
  78. (* rough estimate: digits ~ length - q= and 3 separators
  79. * bits = digits * ln(10)/ln(2)
  80. * geohash has 5 bit per char, *)
  81. float ((qs |> String.length) - 5) *. 3.3219 /. 5.
  82. |> ceil |> truncate
  83. (* but no less than 2 and no more than 12 *)
  84. |> max 2
  85. |> min 12
  86. in
  87. match co |> Geohash.encode prec with
  88. | Error _ -> error oc 406 "Cannot encode coords."
  89. | Ok hash -> hash |> redirect oc)))
  90. | _ -> handle_hash oc req)
  91. | _ -> error oc 405 "Method Not Allowed"