ev/net.rb in rwdtinker-1.67 vs ev/net.rb in rwdtinker-1.68
- old
+ new
@@ -1,7 +1,8 @@
require "ev/ruby"
require "ev/ftools"
+require "ev/mime"
require "net/http"
require "socket"
require "uri"
require "cgi"
require "md5"
@@ -11,15 +12,15 @@
file = "#{home}/.evnet"
if File.file?(file)
Hash.file(file).each do |k, v|
eval "$#{k} = '#{v}'" unless k=~ /^\#/
- #$proxy_auth = [$proxy_auth].pack("m").chomp if k == "proxy_auth"
end
end
def uri2txt(s)
+ # ??? Werkt niet goed
i = s.index(/%[[:digit:]]{2}/)
while not i.nil?
s = s[0..(i-1)] + s[(i+1)..(i+2)].unpack('H2').shift.to_i.chr + s[(i+3)..-1]
i = s.index(/%[[:digit:]]{2}/)
end
@@ -145,10 +146,12 @@
begin
@protocol, @userpass, @host, @port, d1, @path, d2, @vars, @anchor = URI.split(url.to_s)
rescue
end
+ @path = "/" if (not @path.nil? and @path.empty? and @protocol == "http")
+
@protocol = "" if @protocol.nil?
@userpass = "" if @userpass.nil?
@host = "" if @host.nil?
@port = 0 if @port.nil?
@path = "" if @path.nil?
@@ -161,22 +164,22 @@
@vars = res
@port = @port.to_i
end
- def + (url2)
+ def +(url2)
url1 = self.to_s
url2 = url2.to_s if url2.kind_of?(self.class)
return EVURI.new((URI::Generic.new(*URI.split(url1)) + URI::Generic.new(*URI.split(url2))).to_s) rescue nil
end
def to_s
protocol = @protocol
userpass = @userpass
host = @host
- port = @port.to_s
+ port = @port
path = @path
vars = varstring
anchor = @anchor
protocol = nil if @protocol.empty?
@@ -194,10 +197,37 @@
res.gsub!(/\#$/, "")
return res
end
+ def localname
+ protocol = @protocol
+ userpass = @userpass
+ host = @host
+ port = @port
+ path = @path
+ vars = varstring
+ anchor = @anchor
+
+ protocol = nil if @protocol.empty?
+ userpass = nil if @userpass.empty?
+ host = nil if @host.empty?
+ port = nil if @port.zero?
+ path = nil if @path.empty?
+ vars = nil if @vars.empty?
+ anchor = nil if @anchor.empty?
+
+ path = "#{path}." if path =~ /[\/\\]$/
+
+ f = MD5.new(protocol.to_s + userpass.to_s + host.to_s + port.to_s + File.dirname(path.to_s) + vars.to_s).to_s
+ e = File.basename(path.to_s).gsub(/[^\w\.\-]/, "_").gsub(/_+/, "_")
+ res = f + "." + e
+ res.gsub!(/[^\w]+$/, "")
+
+ return res
+ end
+
def varstring
res = []
vars = @vars.dup
@varsvolgorde.each do |k|
@@ -279,115 +309,146 @@
def to_s
@data
end
end
+ class NoAddressException < StandardError
+ end
+
+ def self.getaddress(host)
+ if not @@hosts.include?(host)
+ @@hosts[host] = ""
+ evtimeout(5) do # ??? Doet 'ut niet?...
+ @@hosts[host] = IPSocket.getaddress(host)
+ end
+ end
+
+ raise NoAddressException, host if @@hosts[host].empty?
+
+ @@hosts[host]
+ end
+
def self.head(uri, form={}, recursive=true)
header = Header.new(nil)
begin
while not uri.nil?
- if $proxy.nil? or $proxy.empty?
- uri = EVURI.new(uri) if uri.kind_of? String
- host = uri.host
- port = uri.port
+ uri = EVURI.new(uri) if uri.kind_of? String
+ host = uri.host
+ port = uri.port
+
+ if $proxy.nil? or $proxy.empty? or host == "localhost"
io = nil
@@mutex.synchronize do
- @@hosts[host] = IPSocket.getaddress(host) if not @@hosts.include?(host)
- io = TCPSocket.new(@@hosts[host], port.zero? ? 80 : port)
+ io = TCPSocket.new(getaddress(host), port.zero? ? 80 : port)
end
io.write("HEAD #{uri.path or '/'}#{uri.varstring.empty? ? '' : '?' + uri.varstring} HTTP/1.0\r\nHost: #{host}\r\n\r\n")
else
proxy = EVURI.new($proxy)
- host = proxy.host
- port = proxy.port
+ io = TCPSocket.new(proxy.host, proxy.port.zero? ? 8080 : proxy.port)
- io = TCPSocket.new(host, port.zero? ? 8080 : port)
-
io.write("HEAD #{uri} HTTP/1.0\r\n#{"Proxy-Authorization: Basic "+$proxy_auth+"\r\n" if not $proxy_auth.nil?}\r\n\r\n")
end
io.close_write
- res = io.read
+ res = io.read
+
+ io.close_read
+
header, data = nil, nil
header, data = res.split(/\r*\n\r*\n/, 2) if not res.nil?
header = Header.new(header)
if recursive and header.header["location"] != uri.to_s
uri = EVURI.new(uri) + header.header["location"]
else
uri = nil
end
end
- rescue
+ rescue Errno::ECONNRESET, Errno::EHOSTUNREACH => e
+ $stderr.puts e.message
+ sleep 1
+ retry
+ rescue Errno::ECONNREFUSED => e
+ data = nil
+ rescue NoAddressException => e
+ $stderr.puts e.message
header = Header.new(nil)
end
+ GC.start
+
return header
end
- def self.get(uri, form={})
+ def self.get(uri, httpheader={}, form={})
post = Array.new
form.each_pair do |var, value|
post << "#{var.to_html}=#{value.to_html}"
end
post = post.join("?")
data = nil
begin
while not uri.nil?
- if $proxy.nil? or $proxy.empty?
- uri = EVURI.new(uri) if uri.kind_of? String
- host = uri.host
- port = uri.port
+ uri = EVURI.new(uri) if uri.kind_of? String
+ host = uri.host
+ port = uri.port
+ if $proxy.nil? or $proxy.empty? or host == "localhost"
io = nil
@@mutex.synchronize do
- @@hosts[host] = IPSocket.getaddress(host) if not @@hosts.include?(host)
- io = TCPSocket.new(@@hosts[host], port.zero? ? 80 : port)
+ io = TCPSocket.new(getaddress(host), port.zero? ? 80 : port)
end
if post.empty?
io.write "GET %s%s HTTP/1.0\r\n" % [(uri.path or '/'), (uri.varstring.empty? ? '' : '?' + uri.varstring)]
else
io.write "POST %s%s HTTP/1.0\r\n" % [(uri.path or '/'), (uri.varstring.empty? ? '' : '?' + uri.varstring)]
end
else
proxy = EVURI.new($proxy)
- host = proxy.host
- port = proxy.port
+ io = TCPSocket.new(proxy.host, proxy.port.zero? ? 8080 : proxy.port)
- io = TCPSocket.new(host, port.zero? ? 8080 : port)
-
if post.empty?
io.write "GET %s HTTP/1.0\r\n" % uri
else
io.write "POST %s HTTP/1.0\r\n" % uri
end
end
io.write "Host: %s\r\n" % host
- io.write "User-Agent: evwget\r\n"
- io.write "Proxy-Authorization: Basic %s\r\n" % $proxy_auth unless $proxy_auth.nil?
+ io.write "User-Agent: xyz\r\n"
+ io.write "Proxy-Authorization: Basic %s\r\n" % $proxy_auth unless $proxy_auth.nil?
#io.write "Accept-Encoding: deflate\r\n"
- #io.write "Connection: close\r\n"
+ #io.write "Accept-Charset: ISO-8859-1\r\n"
+ io.write "Connection: close\r\n"
io.write "Content-Type: application/x-www-form-urlencoded\r\n" unless post.empty?
io.write "Content-Length: %s\r\n" % post.length unless post.empty?
+ httpheader.each do |k, v|
+ $stderr.puts "%s: %s\r\n" % [k, v]
+ io.write "%s: %s\r\n" % [k, v]
+ end
io.write "\r\n"
io.write post unless post.empty?
io.close_write
res = io.read
+
+ io.close_read
+
header, data = nil, nil
header, data = res.split(/\r*\n\r*\n/, 2) if not res.nil?
header = Header.new(header)
+ length = header.header["content-length"]
+ data = "" if length == "0"
if header.header["location"] != uri.to_s
uri = EVURI.new(uri) + header.header["location"]
else
uri = nil
@@ -395,16 +456,29 @@
if header.header["transfer-encoding"] == "chunked"
data = Chunk.new(data).to_s if not data.nil?
end
+ #if header.header["content-encoding"] == "gzip"
+ #data = "gzip -d".exec(data) if not data.nil?
+ #end
+
data = nil unless header.code == 200
end
- rescue
+ rescue Errno::ECONNRESET, Errno::EHOSTUNREACH => e
+ $stderr.puts e.message
+ sleep 1
+ retry
+ rescue Errno::ECONNREFUSED => e
data = nil
+ rescue NoAddressException, Errno::ECONNREFUSED => e
+ $stderr.puts e.message
+ data = nil
end
+ GC.start
+
return data
end
def self.head_from_cache(uri, form={})
from_cache("head", uri, form)
@@ -420,11 +494,11 @@
dir = "#{temp}/evcache.#{user}/httpclient.#{action}"
file = "#{dir}/#{hash}"
data = nil
- Dir.mkdirrec(dir)
+ File.mkpath(dir)
expire = 356*24*60*60
if File.file?(file) and (Time.new.to_f - File.stat(file).mtime.to_f < expire)
@@mutex.synchronize do
@@ -445,19 +519,19 @@
end
class RequestGet < Hash
def initialize(data)
CGI.parse(data).each do |k, v|
- self[k] = v.join(" ")
+ self[k] = v
end
end
end
class RequestPost < Hash
def initialize(data)
CGI.parse(data).each do |k, v|
- self[k] = v.join(" ")
+ self[k] = v
end
end
end
class RequestRequest
@@ -491,10 +565,12 @@
class Request < Hash
attr_reader :peeraddr
attr_reader :request
attr_reader :cookies
attr_reader :vars
+ attr_reader :user
+ attr_writer :user
def initialize(io)
@io = io
firstline = @io.gets
@@ -560,10 +636,11 @@
end
end
class Response < Hash
attr_writer :response
+ attr_writer :file
attr_reader :cookies
attr_reader :stop
attr_reader :at_stop
def initialize(io)
@@ -572,14 +649,24 @@
@cookies = {}
@data = ""
@syncd = false
@stop = false
@at_stop = lambda{}
+ @file = nil
end
def flush
sync
+
+ if @file
+ File.open(@file, "rb") do |f|
+ while data = f.read(10_000)
+ @io.write data
+ end
+ end
+ end
+
@io.close
end
def to_s
res = "#{@response}\r\n"
@@ -593,20 +680,39 @@
res
end
def sync
+ size = (@data or "").length
+
+ if @file
+ ext = @file.scan(/\.[^\.]*$/)
+ ext = ext.shift
+ ext = ext[1..-1] unless ext.nil?
+ mimetype = EVMime::MimeType[ext]
+
+ self["Content-Type"] = mimetype unless mimetype.nil?
+
+ size += File.size(@file) if File.file?(@file)
+ end
+
+ self["Content-Length"] = size
+
@io.write("#{to_s}\r\n") unless @syncd
@io.write(@data)
@data = ""
@syncd = true
end
def << (s)
@data << s
end
+ def clean
+ @data = ""
+ end
+
def inspect
"(Response: %s)" % [@response, @data].join(", ")
end
def stop(&block)
@@ -638,11 +744,11 @@
if not server.nil?
count = 0
at_exit do
- $stderr.puts "Received #{count} requests"
+ #$stderr.puts "Received #{count} requests"
end
serverthread =
Thread.new do
mutex = Mutex.new
@@ -676,19 +782,29 @@
rescue NameError
raise HTTPServerException
end
if (not remote) or (remote and (auth.nil? or auth.empty? or authenticate(auth, realm, req, resp)))
- $stderr.puts "#{count2}, #{Time.new.strftime("%Y-%m-%d.%H:%M:%S")}, #{ip}, #{req.request.to_s.strip}"
+ $stderr.puts "#{count2} #{Time.new.strftime("%Y-%m-%d %H:%M:%S")} #{ip} #{req.user} #{req.request.to_s.strip}"
begin
yield(req, resp)
rescue Exception => e
mutex.synchronize do
$stderr.puts e.class.to_s + ": " + e.message
$stderr.puts e.backtrace.collect{|s| "\t"+s}.join("\n")
end
+ resp["Content-Type"] = "text/plain"
+ resp.response = "HTTP/1.0 200 ???"
+ resp.clean
+ resp << e.class.to_s + ": " + e.message
+ resp << "\n"
+ resp << "\n"
+ resp << e.backtrace.collect{|s| "\t"+s}.join("\n")
+ resp << "\n"
+ resp << "\n"
+ resp << "(You can use the back button and stop the application properly, if appropriate.)"
end
stop = true if resp.stop?
end
@@ -736,15 +852,15 @@
end
end
ok = (auths.include?(u) and auths[u] == p)
- if ok
-
- else
+ unless ok
resp["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
resp.response = "HTTP/1.0 401 Unauthorized"
end
+
+ req.user = u
return ok
end
end