femtows 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|