browser.cgi 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/env python3
  2. # vim: tabstop=4 shiftwidth=4 expandtab
  3. import gemcall
  4. import gemtextparser
  5. import urllib.parse
  6. import sys
  7. from os import getenv
  8. urllib.parse.uses_relative.append("gemini")
  9. urllib.parse.uses_netloc.append("gemini")
  10. def clean(text):
  11. return text.replace('<','&lt;').replace('>','&gt;')
  12. print("Content-type: text/html\n\n")
  13. if getenv('QUERY_STRING'):
  14. try:
  15. baseurl = getenv('QUERY_STRING').split('?')[0]
  16. response = gemcall.request(baseurl)
  17. if response.responsecode in [30, 31]:
  18. newtarget = urllib.parse.urljoin(baseurl, response.meta)
  19. print(f"<h1>RESPONSE: \"{str(response.responsecode)} {response.meta}\"</h1><p>This address redirects to <a href='{newtarget}'>{newtarget}</a>.</p>")
  20. elif response.responsecode == 20 and "text/" in response.meta:
  21. responsetext = response.read(20*1024) # We don't support more than 20kb
  22. if "text/gemini" in response.meta:
  23. parser = gemtextparser.GemtextParser()
  24. preform = False
  25. listmode = False
  26. blockquote = False
  27. for line in parser.parseText(responsetext.decode()):
  28. if line.linetype == gemtextparser.LineType.PREFORM:
  29. if not preform:
  30. print("<pre><code>")
  31. preform = True
  32. print(clean(line.text()))
  33. continue
  34. if not line.linetype == gemtextparser.LineType.PREFORM and preform:
  35. print("</code></pre>")
  36. preform = False
  37. if line.linetype == gemtextparser.LineType.LISTITEM:
  38. if not listmode:
  39. print("<ul>")
  40. listmode = True
  41. print(f"<li>{clean(line.text())}</li>")
  42. continue
  43. if not line.linetype == gemtextparser.LineType.LISTITEM and listmode:
  44. print("</ul>")
  45. listmode = False
  46. if line.linetype == gemtextparser.LineType.BLOCKQUOTE:
  47. if not blockquote:
  48. print("<blockquote>")
  49. blockquote = True
  50. print(clean(line.text()))
  51. continue
  52. if not line.linetype == gemtextparser.LineType.BLOCKQUOTE and blockquote:
  53. print("</blockquote>")
  54. blockquote = False
  55. if line.linetype == gemtextparser.LineType.H1 and line.text():
  56. print(f"<h1>{clean(line.text())}</h1>")
  57. continue
  58. if line.linetype == gemtextparser.LineType.H2 and line.text():
  59. print(f"<h2>{clean(line.text())}</h2>")
  60. continue
  61. if line.linetype == gemtextparser.LineType.H3 and line.text():
  62. print(f"<h3>{clean(line.text())}</h3>")
  63. continue
  64. if line.linetype == gemtextparser.LineType.LINK:
  65. linkURL = urllib.parse.urljoin(baseurl, clean(line.linkURL().replace("'","")))
  66. target = "" if linkURL.startswith("gemini://") else " target='_blank'"
  67. if line.text():
  68. print(f"<a href='{linkURL}'{target}>{clean(line.text())}</a><br/>")
  69. else:
  70. print(f"<a href='{linkURL}'{target}>{linkURL}</a><br/>")
  71. continue
  72. if line.linetype == gemtextparser.LineType.PLAIN:
  73. print(f"{clean(line.text())}<br/>")
  74. if listmode:
  75. print("</ul>")
  76. if blockquote:
  77. print("</blockquote>")
  78. if preform:
  79. print("</code></pre>")
  80. else:
  81. print("<pre><code>")
  82. print(clean(responsetext.decode()))
  83. print("</code></pre>")
  84. elif response.responsecode == 20:
  85. print(f"<h1>RESPONSE: \"20 Success\", but...</h1><p>The Wobbly browser only supports text responses, and this response is '{clean(response.meta)}'.</p>")
  86. elif response.responsecode in [40, 41, 42, 43, 44, 50, 51, 52, 53, 59]:
  87. print(f"<h1>RESPONSE: \"{str(response.responsecode)} {clean(response.meta)}\"</h1><p>This is an error message from the server. Hopefully it makes sense to you.</p>")
  88. elif response.responsecode in [60, 61, 62]:
  89. print(f"<h1>RESPONSE: \"{str(response.responsecode)} {clean(response.meta)}\"</h1><p>The Wobbly browser does not support client certificates. Please install a more full-featured browser to visit this page.</p>")
  90. elif response.responsecode in [10,11]:
  91. print(f"<h1>RESPONSE: \"{str(response.responsecode)} {clean(response.meta)}\"</h1><p>The status codes 10 and 11 are requests for user input.</p><p>The only means of submitting user input to a server in gemini is via the so-called QUERY_STRING; the part of a URL that follows after a '?'. The Wobbly browser does not support this for privacy/security reasons. Please install a more full-featured browser to be able to submit data.</p>")
  92. response.discard()
  93. except:
  94. print(f"<h1>Unknown Error</h1><p>Something went wrong when trying to fetch '{getenv('QUERY_STRING')}'. Could not recover.</p>")
  95. else:
  96. print("<h1>What?</h1><p>I'm sorry, but I don't know what you want me to do without a URL.</p>")