aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar √Čtienne Deparis 2020-11-24 20:16:54 +0100
committerGravatar √Čtienne Deparis 2020-11-24 20:16:54 +0100
commitf88d1840875f117fb328ceb80fb717497e425727 (patch)
tree599b12aa710717ab9c0962f695b7c8ea01eaa041
parentfb926ee50880e3e5ec925a4a8d5de79e68a60929 (diff)
downloadruby-net-text-support-gopher.tar.gz
ruby-net-text-support-gopher.tar.xz
ruby-net-text-support-gopher.zip
wip: Begin to work on gophersupport-gopher
-rwxr-xr-xbin/heraut35
-rw-r--r--lib/net/gemini/request.rb5
-rw-r--r--lib/net/gopher.rb105
-rw-r--r--lib/uri/gopher.rb17
4 files changed, 145 insertions, 17 deletions
diff --git a/bin/heraut b/bin/heraut
index 8168ebb..e237902 100755
--- a/bin/heraut
+++ b/bin/heraut
@@ -2,21 +2,28 @@
# frozen_string_literal: true
require 'net/gemini'
+require 'net/gopher'
u = URI(ARGV[0])
-response = Net::Gemini.get_response u
-puts response.body(flowed: 78)
-puts "\n* Headers"
-puts "#{response.status} - #{response.meta}"
-response.header.each do |k, v|
- puts "- #{k} :: #{v}"
-end
-puts "\n* Links"
-links = response.links.map do |l|
- if l[:label]
- "- #{l[:label]}: #{l[:uri]}"
- else
- "- #{l[:uri]}"
+
+case u.scheme
+when 'gemini'
+ response = Net::Gemini.get_response u
+ puts response.body(flowed: 78)
+ puts "\n* Headers"
+ puts "#{response.status} - #{response.meta}"
+ response.header.each do |k, v|
+ puts "- #{k} :: #{v}"
+ end
+ puts "\n* Links"
+ links = response.links.map do |l|
+ if l[:label]
+ "- #{l[:label]}: #{l[:uri]}"
+ else
+ "- #{l[:uri]}"
+ end
end
+ puts links.join("\n")
+when 'gopher'
+ Net::Gopher.get_response(u)
end
-puts links.join("\n")
diff --git a/lib/net/gemini/request.rb b/lib/net/gemini/request.rb
index 28ce66e..4706d06 100644
--- a/lib/net/gemini/request.rb
+++ b/lib/net/gemini/request.rb
@@ -23,9 +23,8 @@ module Net
raise GeminiBadRequest, "Request too long: #{url.dump}"
end
@uri = URI(url)
- unless uri.is_a? URI::Gemini
- raise GeminiBadRequest, "Not a Gemini URI: #{url.dump}"
- end
+ return if uri.is_a? URI::Gemini
+ raise GeminiBadRequest, "Not a Gemini URI: #{url.dump}"
end
def path
diff --git a/lib/net/gopher.rb b/lib/net/gopher.rb
new file mode 100644
index 0000000..333836b
--- /dev/null
+++ b/lib/net/gopher.rb
@@ -0,0 +1,105 @@
+# frozen_string_literal: true
+
+# This file is derived from "net/http.rb".
+
+require 'socket'
+require 'fileutils'
+
+require 'uri/gopher'
+
+module Net
+ class GopherError < StandardError; end
+
+ # == A Gopher client API for Ruby.
+ #
+ # Net::Gopher provides a rich library which can be used to build
+ # Gopher user-agents.
+ #
+ # Net::Gopher is designed to work closely with URI.
+ #
+ # == Simple Examples
+ #
+ # All examples assume you have loaded Net::Gopher with:
+ #
+ # require 'net/gopher'
+ #
+ # This will also require 'uri' so you don't need to require it
+ # separately.
+ #
+ # The Net::Gopher methods in the following section do not persist
+ # connections.
+ #
+ # === GET by URI
+ #
+ # uri = URI('gopher://thelambdalab.xyz/1/projects/elpher/')
+ # Net::Gopher.get(uri) # => String
+ #
+ # === GET with Dynamic Parameters
+ #
+ # uri = URI('')
+ # params = { :limit => 10, :page => 3 }
+ # uri.query = URI.encode_www_form(params)
+ #
+ # res = Net::Gopher.get_response(uri)
+ # puts res.body if res.body_permitted?
+ #
+ # === Response Data
+ #
+ # res = Net::Gopher.get_response(URI('gopher://exemple.com/home'))
+ #
+ # # Status
+ # puts res.status # => '20'
+ # puts res.meta # => 'text/gopher; charset=UTF-8; lang=en'
+ #
+ # # Headers
+ # puts res.header.inspect
+ # # => { status: '20', meta: 'text/gopher; charset=UTF-8',
+ # mimetype: 'text/gopher', lang: 'en',
+ # charset: 'utf-8', format: nil }
+ #
+ # The lang, charset and format headers will only be provided in case
+ # of `text/*` mimetype, and only if body for 2* status codes.
+ #
+ # # Body
+ # puts res.body if res.body_permitted?
+ # puts res.body(flowed: 85)
+ #
+ class Gopher
+ def initialize(host, port)
+ @host = host
+ @port = port
+ end
+
+ def request(uri)
+ sock = TCPSocket.new(@host, @port)
+ sock.puts "#{uri.selector}\r\n"
+ puts sock.read
+ ensure
+ # Stop remaining connection, even if they should be already cut
+ # by the server
+ sock&.close
+ end
+
+ class << self
+ def start(host_or_uri, port = nil)
+ if host_or_uri.is_a? URI::Gopher
+ host = host_or_uri.host
+ port = host_or_uri.port
+ else
+ host = host_or_uri
+ end
+ gopher = new(host, port)
+ return yield(gopher) if block_given?
+ gopher
+ end
+
+ def get_response(uri)
+ start(uri.host, uri.port) { |gopher| gopher.request(uri) }
+ end
+
+ def get(uri)
+ get_response(uri).body
+ end
+ end
+ end
+end
diff --git a/lib/uri/gopher.rb b/lib/uri/gopher.rb
index e99c32b..b737692 100644
--- a/lib/uri/gopher.rb
+++ b/lib/uri/gopher.rb
@@ -15,6 +15,23 @@ module URI # :nodoc:
# An Array of the available components for URI::Gopher.
COMPONENT = [:scheme, :host, :port, :path].freeze
+
+ def selector
+ return @selector if defined? @selector
+ @selector = extract_gopher_path_elements[1]
+ end
+
+ def item_type
+ return @item_type if defined? @item_type
+ @item_type = extract_gopher_path_elements[0]
+ end
+
+ private
+
+ def extract_gopher_path_elements
+ m = /\A\/([0-9+dfghisA-LT])(\/.*)?\Z/.match(@path)
+ m.captures
+ end
end
@@schemes['GOPHER'] = Gopher