femtows 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/femtows.bat +0 -0
- data/bin/femtows.sh +2 -2
- data/gitc.bat +20 -0
- data/lib/femtows.rb +263 -262
- metadata +12 -13
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cb91e5bf92627376e1417d32a8c897ac196510f6
|
4
|
+
data.tar.gz: 5c1667b4230b70efbb72e565078765b1ccf6d0cd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f4ff73c70c9654078d76304b054662e06be080d230b64cec0c1fffdab2a425ba8c3beda4f6db170cc1c3608dd8d21ce23262c0665880154c201a96523c3e1764
|
7
|
+
data.tar.gz: 77732c765e07894cfa92f266d9a8109b126dce1fbf41b9b39a8cafbf0cb59263c3e2f3cbbfa352e94061a88c630c2cb24e0fd47745551ce03d90f840916508b0
|
data/bin/femtows.bat
CHANGED
File without changes
|
data/bin/femtows.sh
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require 'femtows'
|
2
|
-
cliweb((ARGV[1]||"./"),(ARGV[0]||"8080").to_i)
|
1
|
+
require 'femtows'
|
2
|
+
cliweb((ARGV[1]||"./"),(ARGV[0]||"8080").to_i)
|
data/gitc.bat
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
@echo off
|
2
|
+
IF DEFINED %1=="" (
|
3
|
+
call giti
|
4
|
+
ruby -e "a=File.read('VERSION').split('.') ; a[-1]=(a.last.to_i+1).to_s; puts r=a.join('.'); File.open('VERSION','w') {|f| f.write(r)}"
|
5
|
+
echo %1 %2 %3 %4 %5 %6 %7 %8 %9 >> CHANGELOG.txt
|
6
|
+
git commit -a -m "%1 %2 %3 %4 %5 %6 %7 %8 %9"
|
7
|
+
git push
|
8
|
+
echo
|
9
|
+
echo call gitc.bat without args for make/post rubygem
|
10
|
+
goto :eof
|
11
|
+
)
|
12
|
+
:gem
|
13
|
+
rem ==== no args, generate gem and push it to rubygems.org
|
14
|
+
|
15
|
+
ruby -e "a=File.read('VERSION').split('.');a.pop ; a[-1]=(a.last.to_i+1).to_s; puts r=(a+[0]).join('.'); File.open('VERSION','w') {|f| f.puts(r)}"
|
16
|
+
cat VERSION >> CHANGELOG.txt
|
17
|
+
|
18
|
+
ruby -e "Dir.glob('femtows*.gem').each {|f| File.delete(f) }"
|
19
|
+
call gem build femtows.gemspec
|
20
|
+
call gem push femtows*.gem
|
data/lib/femtows.rb
CHANGED
@@ -1,262 +1,263 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# FemtoWebServer : 232 LOC web server
|
3
|
-
#
|
4
|
-
# $ws=WebserverRoot.new(port,"/home/www","femto ws",10,300)
|
5
|
-
# ws.serve "/FOO" do |params|
|
6
|
-
# data=params["HEAD-DATA"]|| ""
|
7
|
-
# puts "Recu data len=#{data.length} : <#{data[0..1000]}>" if data
|
8
|
-
# [200,".json",""]
|
9
|
-
# end
|
10
|
-
|
11
|
-
|
12
|
-
require 'thread'
|
13
|
-
require 'socket'
|
14
|
-
require 'timeout'
|
15
|
-
|
16
|
-
#################### Tiny embeded webserver
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
class WebserverAbstract
|
22
|
-
def logg(*args)
|
23
|
-
if @cb_log then @cb_log.call(@name,*args) else puts(args.join(" ")) end
|
24
|
-
rescue
|
25
|
-
puts(args.join(" "))
|
26
|
-
end
|
27
|
-
def info(txt) ; logg("nw>i>",txt) ; end
|
28
|
-
def error(txt) ; logg("nw>e>",txt) ; end
|
29
|
-
def unescape(string) ; string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2}))/n) { [$1.delete('%')].pack('H*') }
|
30
|
-
def escape(string) ; string.gsub(/([^ \/a-zA-Z0-9_
|
31
|
-
def hescape(string) ; escape(string.gsub("/./","/").gsub("//","/")) ; end
|
32
|
-
def observe(sleeping,delta)
|
33
|
-
@tho=Thread.new do loop do
|
34
|
-
sleep(sleeping)
|
35
|
-
nowDelta=Time.now-delta
|
36
|
-
l=@th.select { |th,tm| (tm[0]<nowDelta) }
|
37
|
-
l.each { |th,tm| info("killing thread") ; th.kill; @th.delete(th) ; tm[1].close rescue nil }
|
38
|
-
end ; end
|
39
|
-
end
|
40
|
-
def initialize(port,root,name,cadence,timeout,options)
|
41
|
-
raise("tcp port illegal #{port}") unless port.to_i>=80
|
42
|
-
raise("root not exist #{root}") unless File.exists?(root)
|
43
|
-
@cb_log= options["logg"]
|
44
|
-
@last_mtime=File.mtime(__FILE__)
|
45
|
-
@port=port.to_i
|
46
|
-
@root=root
|
47
|
-
@name=name
|
48
|
-
@rootd=root[-1,1]=="/" ? root : root+"/"
|
49
|
-
@timeout=timeout
|
50
|
-
@th={}
|
51
|
-
@cb={}
|
52
|
-
@redirect={}
|
53
|
-
info(" serveur http #{port} on #{@rootd} ready!")
|
54
|
-
observe(cadence,timeout*2)
|
55
|
-
pool_create
|
56
|
-
@thm=Thread.new {
|
57
|
-
loop {
|
58
|
-
nbError=0
|
59
|
-
begin
|
60
|
-
session=nil
|
61
|
-
@server = TCPServer.new('0.0.0.0', @port)
|
62
|
-
@server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
63
|
-
while (session = @server.accept)
|
64
|
-
nbError=0
|
65
|
-
run(session)
|
66
|
-
end
|
67
|
-
rescue Exception => e
|
68
|
-
nbError+=1
|
69
|
-
error($!.to_s + " " + $!.backtrace[0..2].join(" "))
|
70
|
-
session.close rescue nil
|
71
|
-
@server.close rescue nil
|
72
|
-
end
|
73
|
-
sleep(3); info("restart accept")
|
74
|
-
}
|
75
|
-
}
|
76
|
-
end
|
77
|
-
def pool_create
|
78
|
-
@queue=Queue.new
|
79
|
-
ici=self
|
80
|
-
100.times { Thread.new { loop {
|
81
|
-
param,bloc=@queue.pop
|
82
|
-
bloc.call(param) rescue p $!
|
83
|
-
} } }
|
84
|
-
end
|
85
|
-
def pool_get(param,&block)
|
86
|
-
@queue.push([param,block])
|
87
|
-
end
|
88
|
-
def run(session)
|
89
|
-
pool_get(session) do |sess|
|
90
|
-
@th[Thread.current]=[Time.now,sess]
|
91
|
-
request(sess)
|
92
|
-
@th.delete(Thread.current)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
def serve(uri,&blk)
|
96
|
-
@cb[uri] = blk
|
97
|
-
end
|
98
|
-
def request(session)
|
99
|
-
request = session.gets
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
params.
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
head.
|
122
|
-
|
123
|
-
|
124
|
-
params["HEAD-CONTENT-LENGTH"]
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
@
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
updir="/"
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
def
|
185
|
-
def
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
sock.write(content
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
File.
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
def
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
"
|
236
|
-
"
|
237
|
-
"
|
238
|
-
"
|
239
|
-
"
|
240
|
-
"
|
241
|
-
"
|
242
|
-
"
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
end
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
end
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
# FemtoWebServer : 232 LOC web server
|
3
|
+
#
|
4
|
+
# $ws=WebserverRoot.new(port,"/home/www","femto ws",10,300)
|
5
|
+
# ws.serve "/FOO" do |params|
|
6
|
+
# data=params["HEAD-DATA"]|| ""
|
7
|
+
# puts "Recu data len=#{data.length} : <#{data[0..1000]}>" if data
|
8
|
+
# [200,".json",""]
|
9
|
+
# end
|
10
|
+
|
11
|
+
|
12
|
+
require 'thread'
|
13
|
+
require 'socket'
|
14
|
+
require 'timeout'
|
15
|
+
|
16
|
+
#################### Tiny embeded webserver
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
class WebserverAbstract
|
22
|
+
def logg(*args)
|
23
|
+
if @cb_log then @cb_log.call(@name,*args) else puts(args.join(" ")) end
|
24
|
+
rescue
|
25
|
+
puts(args.join(" "))
|
26
|
+
end
|
27
|
+
def info(txt) ; logg("nw>i>",txt) ; end
|
28
|
+
def error(txt) ; logg("nw>e>",txt) ; end
|
29
|
+
def unescape(string) ; string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2}))/n) { [$1.delete('%')].pack('H*') } end
|
30
|
+
def escape(string) ; string.gsub(/([^ \/a-zA-Z0-9_.\-]+)/) { '%' + $1.unpack('H2' * $1.size).join('%').upcase }.tr(' ', '+') end
|
31
|
+
def hescape(string) ; escape(string.gsub("/./","/").gsub("//","/")) ; end
|
32
|
+
def observe(sleeping,delta)
|
33
|
+
@tho=Thread.new do loop do
|
34
|
+
sleep(sleeping)
|
35
|
+
nowDelta=Time.now-delta
|
36
|
+
l=@th.select { |th,tm| (tm[0]<nowDelta) }
|
37
|
+
l.each { |th,tm| info("killing thread") ; th.kill; @th.delete(th) ; tm[1].close rescue nil }
|
38
|
+
end ; end
|
39
|
+
end
|
40
|
+
def initialize(port,root,name,cadence,timeout,options)
|
41
|
+
raise("tcp port illegal #{port}") unless port.to_i>=80
|
42
|
+
raise("root not exist #{root}") unless File.exists?(root)
|
43
|
+
@cb_log= options["logg"]
|
44
|
+
@last_mtime=File.mtime(__FILE__)
|
45
|
+
@port=port.to_i
|
46
|
+
@root=root
|
47
|
+
@name=name
|
48
|
+
@rootd=root[-1,1]=="/" ? root : root+"/"
|
49
|
+
@timeout=timeout
|
50
|
+
@th={}
|
51
|
+
@cb={}
|
52
|
+
@redirect={}
|
53
|
+
info(" serveur http #{port} on #{@rootd} ready!")
|
54
|
+
observe(cadence,timeout*2)
|
55
|
+
pool_create
|
56
|
+
@thm=Thread.new {
|
57
|
+
loop {
|
58
|
+
nbError=0
|
59
|
+
begin
|
60
|
+
session=nil
|
61
|
+
@server = TCPServer.new('0.0.0.0', @port)
|
62
|
+
@server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
63
|
+
while (session = @server.accept)
|
64
|
+
nbError=0
|
65
|
+
run(session)
|
66
|
+
end
|
67
|
+
rescue Exception => e
|
68
|
+
nbError+=1
|
69
|
+
error($!.to_s + " " + $!.backtrace[0..2].join(" "))
|
70
|
+
session.close rescue nil
|
71
|
+
@server.close rescue nil
|
72
|
+
end
|
73
|
+
sleep(3); info("restart accept")
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
def pool_create
|
78
|
+
@queue=Queue.new
|
79
|
+
ici=self
|
80
|
+
100.times { Thread.new { loop {
|
81
|
+
param,bloc=@queue.pop
|
82
|
+
bloc.call(param) rescue p $!
|
83
|
+
} } }
|
84
|
+
end
|
85
|
+
def pool_get(param,&block)
|
86
|
+
@queue.push([param,block])
|
87
|
+
end
|
88
|
+
def run(session)
|
89
|
+
pool_get(session) do |sess|
|
90
|
+
@th[Thread.current]=[Time.now,sess]
|
91
|
+
request(sess)
|
92
|
+
@th.delete(Thread.current)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
def serve(uri,&blk)
|
96
|
+
@cb[uri] = blk
|
97
|
+
end
|
98
|
+
def request(session)
|
99
|
+
request = session.gets
|
100
|
+
return unless request
|
101
|
+
uri = (request.split(/\s+/)+['','',''])[1]
|
102
|
+
#info uri
|
103
|
+
service,param,*bidon=(uri+"?").split(/\?/)
|
104
|
+
params=Hash[*(param.split(/#/)[0].split(/[=&]/))] rescue {}
|
105
|
+
params.each { |k,v| params[k]=unescape(v) }
|
106
|
+
uri=unescape(service)[1..-1].gsub(/\.\./,"")
|
107
|
+
userpass=nil
|
108
|
+
if (buri=uri.split(/@/)).size>1
|
109
|
+
uri=buri[1..-1].join("@")
|
110
|
+
userpass=buri[0].split(/:/)
|
111
|
+
end
|
112
|
+
read_header(session,params)
|
113
|
+
do_service(session,request,uri,userpass,params)
|
114
|
+
rescue Exception => e
|
115
|
+
error("Error Web get on #{request}: \n #{$!.to_s} \n #{$!.backtrace.join("\n ")}" ) rescue nil
|
116
|
+
session.write "HTTP/1.0 501 NOK\r\nContent-type: text/html\r\n\r\n<html><head><title>WS</title></head><body>Error : #{$!}" rescue nil
|
117
|
+
ensure
|
118
|
+
session.close rescue nil
|
119
|
+
end
|
120
|
+
def read_header(session,params)
|
121
|
+
head=session.gets("\r\n\r\n")
|
122
|
+
head.split(/\r\n/m).each { |line| name,data=line.split(": ",2) ; params["HEAD-"+name.upcase]=data }
|
123
|
+
if params["HEAD-CONTENT-LENGTH"]
|
124
|
+
len= params["HEAD-CONTENT-LENGTH"].split(/\s+/).last.to_i
|
125
|
+
params["HEAD-CONTENT-LENGTH"]=len
|
126
|
+
data=""
|
127
|
+
while len>0
|
128
|
+
d=session.read(len>64*1024 ? 64*1024 : len)
|
129
|
+
raise("closed") if !d
|
130
|
+
len -= d.length
|
131
|
+
data+=d
|
132
|
+
end
|
133
|
+
params["HEAD-DATA"]=data
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def redirect(o,d)
|
138
|
+
@redirect[o]=d
|
139
|
+
end
|
140
|
+
def do_service(session,request,service,user_passwd,params)
|
141
|
+
redir=@redirect["/"+service]
|
142
|
+
service=redir.gsub(/^\//,"") if @redirect[redir]
|
143
|
+
aservice=to_absolute(service)
|
144
|
+
if redir && ! @redirect[redir]
|
145
|
+
do_service(session,request,redir.gsub(/^\//,""),user_passwd,params)
|
146
|
+
elsif @cb["/"+service]
|
147
|
+
begin
|
148
|
+
code,type,data= @cb["/"+service].call(params)
|
149
|
+
if code==0 && data != '/'+service
|
150
|
+
do_service(session,request,data[1..-1],user_passwd,params)
|
151
|
+
else
|
152
|
+
code==200 ? sendData(session,type,data) : sendError(session,code,data)
|
153
|
+
end
|
154
|
+
rescue
|
155
|
+
logg session.peeraddr.last,"Error in get /#{service} : #{$!}"
|
156
|
+
sendError(session,501,$!.to_s)
|
157
|
+
end
|
158
|
+
elsif service =~ /^stop/
|
159
|
+
sendData(session,".html","Stopping...");
|
160
|
+
Thread.new() { sleep(0.1); stop_browser() }
|
161
|
+
elsif File.directory?(aservice)
|
162
|
+
sendData(session,".html",makeIndex(aservice))
|
163
|
+
elsif File.exists?(aservice)
|
164
|
+
sendFile(session,aservice)
|
165
|
+
else
|
166
|
+
info("unknown request serv=#{service} params=#{params.inspect} #{File.exists?(service)}")
|
167
|
+
sendError(session,500,"unknown request serv=#{aservice} params=#{params.inspect} #{File.exists?(service)}");
|
168
|
+
end
|
169
|
+
end
|
170
|
+
def stop_browser
|
171
|
+
info "exit on web demand !"
|
172
|
+
[@tho,@thm].each { |th| th.kill }
|
173
|
+
@server.close rescue nil
|
174
|
+
end
|
175
|
+
def makeIndex(adir)
|
176
|
+
dir=to_relative(adir)
|
177
|
+
dirs,files=Dir.glob(adir==@rootd ? "#{@rootd}*" : "#{adir}/*").sort.partition { |f| File.directory?(f)}
|
178
|
+
|
179
|
+
updir = hescape( dir.split(/\//)[0..-2].join("/"))
|
180
|
+
updir="/" if updir.length==0
|
181
|
+
up=(dir!="/") ? "<input type='button' onclick='location.href=\"#{updir}\"' value='Parent'>" : ""
|
182
|
+
"<html><head><title>#{dir}</title></head>\n<body><h3><center>#{@name} : #{dir[0..-1]}</center></h3>\n<hr>#{up}<br>#{to_table(dirs.map {|s| " <a href='#{hescape(to_relative(s))}'>"+File.basename(s)+"/"+"</a>\n"})}<hr>#{to_tableb(files) {|f| [" <a href='#{hescape(to_relative(f))}'>"+File.basename(f)+"</a>",n3(File.size(f)),File.mtime(f).strftime("%d/%m/%Y %H:%M:%S")]}}</body></html>"
|
183
|
+
end
|
184
|
+
def to_relative(f) f.gsub(/^#{@rootd}/,"/") end
|
185
|
+
def to_absolute(f) "#{@rootd}#{f.gsub(/^\//,'')}" end
|
186
|
+
def n3(n)
|
187
|
+
u=" B"
|
188
|
+
if n> 10000000
|
189
|
+
n=n/(1024*1024)
|
190
|
+
u=" MB"
|
191
|
+
elsif n> 100000
|
192
|
+
n=n/1024
|
193
|
+
u=" KB"
|
194
|
+
end
|
195
|
+
"<div style='width:100px;text-align:right;'>#{(n.round.to_i.to_s.reverse.gsub(/(\d\d\d)(?=\d)/,'\1 ' ).reverse) +u} | </div>"
|
196
|
+
end
|
197
|
+
def to_table(l)
|
198
|
+
"<table><tr>#{l.map {|s| "<td>#{s}</td>"}.join("</tr><tr>")}</tr></table>"
|
199
|
+
end
|
200
|
+
def to_tableb(l,&bl)
|
201
|
+
"<table><tr>#{l.map {|s| "<td>#{bl.call(s).join("</td><td>")}</td>"}.join("</tr><tr>")}</tr></table>"
|
202
|
+
end
|
203
|
+
def sendError(sock,no,txt=nil)
|
204
|
+
if txt
|
205
|
+
txt="<html><body><code><pre></pre>#{txt}</code></body></html>"
|
206
|
+
end
|
207
|
+
sock.write "HTTP/1.0 #{no} NOK\r\nContent-type: #{mime(".html")}\r\n\r\n <html><p>Error #{no} : #{txt}</p></html>"
|
208
|
+
end
|
209
|
+
def sendData(sock,type,content)
|
210
|
+
sock.write "HTTP/1.0 200 OK\r\nContent-Type: #{mime(type)}\r\nContent-Length: #{content.size}\r\n\r\n"
|
211
|
+
sock.write(content)
|
212
|
+
end
|
213
|
+
def sendFile(sock,filename)
|
214
|
+
s=File.size(filename)
|
215
|
+
if s < 0 || s>60_000_000 || File.extname(filename).downcase==".lnk"
|
216
|
+
logg @name,"Error reading file/File not downloadable #{File.basename(filename)} : (size=#{s})"
|
217
|
+
sendError(sock,500,"Error reading file/File not downloadable #{filename} : (size=#{s})" )
|
218
|
+
return
|
219
|
+
end
|
220
|
+
logg @name,filename," #{s/(1024*1024)} Mo" if s>10*1000_000
|
221
|
+
timeout([s/(512*1024),30.0].max.to_i) {
|
222
|
+
sock.write "HTTP/1.0 200 OK\r\nContent-Type: #{mime(filename)}\r\nContent-Length: #{File.size(filename)}\r\nLast-Modified: #{httpdate(File.mtime(filename))}\r\nDate: #{httpdate(Time.now)}\r\n\r\n"
|
223
|
+
File.open(filename,"rb") do |f|
|
224
|
+
f.binmode; sock.binmode;
|
225
|
+
( sock.write(f.read(32*1024)) while (! f.eof? && ! sock.closed?) ) rescue nil
|
226
|
+
end
|
227
|
+
}
|
228
|
+
end
|
229
|
+
def httpdate( aTime ); (aTime||Time.now).gmtime.strftime( "%a, %d %b %Y %H:%M:%S GMT" ); end
|
230
|
+
def mime(string)
|
231
|
+
MIME[string.split(/\./).last] || "application/octet-stream"
|
232
|
+
end
|
233
|
+
LICON="☀☃☎☑☑☠☣☮☺☂".split(/;/).map {|c| c+";"}
|
234
|
+
MIME={"png" => "image/png", "gif" => "image/gif", "html" => "text/html","htm" => "text/html",
|
235
|
+
"js" => "text/javascript" ,"css" => "text/css","jpeg" => "image/jpeg" ,"jpg" => "image/jpeg",
|
236
|
+
".json" => "applicatipon/json",
|
237
|
+
"pdf"=> "application/pdf" , "svg" => "image/svg+xml","svgz" => "image/svg+xml",
|
238
|
+
"xml" => "text/xml" ,"xsl" => "text/xml" ,"bmp" => "image/bmp" ,"txt" => "text/plain" ,
|
239
|
+
"rb" => "text/plain" ,"pas" => "text/plain" ,"tcl" => "text/plain" ,"java" => "text/plain" ,
|
240
|
+
"c" => "text/plain" ,"h" => "text/plain" ,"cpp" => "text/plain", "xul" => "application/vnd.mozilla.xul+xml",
|
241
|
+
"doc" => "application/msword", "docx" => "application/msword","dot"=> "application/msword",
|
242
|
+
"xls" => "application/vnd.ms-excel","xla" => "application/vnd.ms-excel","xlt" => "application/vnd.ms-excel","xlsx" => "application/vnd.ms-excel",
|
243
|
+
"ppt" => "application/vnd.ms-powerpoint", "pptx" => "application/vnd.ms-powerpoint"
|
244
|
+
}
|
245
|
+
end # 220 loc webserver :)
|
246
|
+
|
247
|
+
class Webserver < WebserverAbstract
|
248
|
+
def initialize(port=7080,cadence=10,timeout=120)
|
249
|
+
super(port,Dir.getwd(),"",cadence,timeout)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
class WebserverRoot < WebserverAbstract
|
253
|
+
def initialize(port=7080,root=".",name="wwww",cadence=10,timeout=120,options={})
|
254
|
+
super(port,root,name,cadence,timeout,options)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
def cliweb(root=Dir.getwd,port=59999)
|
258
|
+
Thread.abort_on_exception = false
|
259
|
+
BasicSocket.do_not_reverse_lookup = true
|
260
|
+
$ws=WebserverRoot.new(port,root,'femto ws',10,300, {});
|
261
|
+
puts "Server root path #{root} with port #{port}"
|
262
|
+
sleep
|
263
|
+
end
|
metadata
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: femtows
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.6.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Glurp man
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-06-18 00:00:00.000000000 Z
|
13
12
|
dependencies: []
|
14
|
-
description:
|
13
|
+
description: "a tiny web server, for local file transfert, \nembedded, http experimentations\n"
|
15
14
|
email: regis.aubarede@gmail.com
|
16
15
|
executables:
|
17
16
|
- femtows.bat
|
@@ -19,33 +18,33 @@ executables:
|
|
19
18
|
extensions: []
|
20
19
|
extra_rdoc_files: []
|
21
20
|
files:
|
21
|
+
- bin/femtows.bat
|
22
|
+
- bin/femtows.sh
|
22
23
|
- demo.rb
|
23
|
-
-
|
24
|
+
- gitc.bat
|
24
25
|
- guidemo.rb
|
25
|
-
-
|
26
|
-
- bin/femtows.bat
|
26
|
+
- lib/femtows.rb
|
27
27
|
homepage: http://github.com/glurp/femtows
|
28
28
|
licenses: []
|
29
|
-
|
29
|
+
metadata: {}
|
30
|
+
post_install_message: "-------------------------------------------------------------------------------\nHello,
|
30
31
|
welcome to Femto Web Server....\n\n$ femtows [port,[root-directory] \n\n-------------------------------------------------------------------------------\n"
|
31
32
|
rdoc_options: []
|
32
33
|
require_paths:
|
33
34
|
- lib
|
34
35
|
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
-
none: false
|
36
36
|
requirements:
|
37
|
-
- -
|
37
|
+
- - '>='
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0'
|
40
40
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
41
|
requirements:
|
43
|
-
- -
|
42
|
+
- - '>='
|
44
43
|
- !ruby/object:Gem::Version
|
45
44
|
version: '0'
|
46
45
|
requirements: []
|
47
46
|
rubyforge_project:
|
48
|
-
rubygems_version:
|
47
|
+
rubygems_version: 2.4.6
|
49
48
|
signing_key:
|
50
49
|
specification_version: 3
|
51
50
|
summary: a tiny webserver
|