Sat, 02 Jan 2010 06:04:12 +0000
demo.lua: Fix and improve progress callback example
0 | 1 | package.preload['util.logger']=(function(...) |
2 | local t; | |
3 | if os.getenv("LAHTTP_DEBUG")then | |
4 | t=_G.print; | |
5 | else | |
6 | t=function()end; | |
7 | end | |
8 | local i,a=select,tostring; | |
9 | module"logger" | |
10 | local function e(t,...) | |
11 | local e,o=0,#arg; | |
12 | return(t:gsub("%%(.)",function(t)if t~="%"and e<=o then e=e+1;return a(arg[e]);end end)); | |
13 | end | |
14 | local function s(n,...) | |
15 | local e,t=0,i('#',...); | |
16 | local o={...}; | |
17 | return(n:gsub("%%(.)",function(i)if e<=t then e=e+1;return a(o[e]);end end)); | |
18 | end | |
19 | function init(e) | |
20 | return function(a,e,...) | |
21 | t(a,s(e,...)); | |
22 | end | |
23 | end | |
24 | return _M; | |
25 | end) | |
26 | package.preload['net.server']=(function(...) | |
27 | local l=function(e) | |
28 | return _G[e] | |
29 | end | |
30 | local J=function(e) | |
31 | for t,a in pairs(e)do | |
32 | e[t]=nil | |
33 | end | |
34 | end | |
35 | local w,e=require("util.logger").init("socket"),table.concat; | |
36 | local n=function(...)return w("debug",e{...});end | |
37 | local H=function(...)return w("warn",e{...});end | |
38 | local e=collectgarbage | |
39 | local ie=1 | |
40 | local A=l"type" | |
41 | local T=l"pairs" | |
42 | local he=l"ipairs" | |
43 | local h=l"tostring" | |
44 | local e=l"collectgarbage" | |
45 | local o=l"os" | |
46 | local a=l"table" | |
47 | local t=l"string" | |
48 | local e=l"coroutine" | |
49 | local V=o.time | |
50 | local R=o.difftime | |
51 | local te=a.concat | |
52 | local a=a.remove | |
53 | local B=t.len | |
54 | local de=t.sub | |
55 | local ue=e.wrap | |
56 | local le=e.yield | |
57 | local I=select(2,pcall(require,"ssl")) | |
58 | local L=require"socket" | |
59 | local ee=(I and I.wrap) | |
60 | local fe=L.bind | |
61 | local me=L.sleep | |
62 | local ce=L.select | |
63 | local e=(I and I.newcontext) | |
64 | local G | |
65 | local X | |
66 | local Z | |
67 | local W | |
68 | local Y | |
69 | local ne | |
70 | local re | |
71 | local se | |
72 | local ae | |
73 | local oe | |
74 | local P | |
75 | local d | |
76 | local Q | |
77 | local t | |
78 | local D | |
79 | local K | |
80 | local p | |
81 | local s | |
82 | local C | |
83 | local r | |
84 | local i | |
85 | local k | |
86 | local b | |
87 | local f | |
88 | local c | |
89 | local a | |
90 | local o | |
91 | local v | |
92 | local U | |
93 | local S | |
94 | local _ | |
95 | local j | |
96 | local M | |
97 | local u | |
98 | local z | |
99 | local x | |
100 | local O | |
101 | local E | |
102 | local q | |
103 | local N | |
104 | local F | |
105 | local g | |
106 | p={} | |
107 | s={} | |
108 | r={} | |
109 | C={} | |
110 | i={} | |
111 | b={} | |
112 | f={} | |
113 | k={} | |
114 | a=0 | |
115 | o=0 | |
116 | v=0 | |
117 | U=0 | |
118 | S=0 | |
119 | _=1 | |
120 | j=0 | |
121 | z=51e3*1024 | |
122 | x=25e3*1024 | |
123 | O=12e5 | |
124 | E=6e4 | |
125 | q=6*60*60 | |
126 | N=false | |
127 | g=1e3 | |
128 | _maxsslhandshake=30 | |
129 | ae=function(y,l,k,u,b,t,p,v) | |
130 | p=p or g | |
131 | local f=0 | |
132 | local g,c=y.onincoming,y.ondisconnect | |
133 | local m | |
134 | local c=false | |
135 | if t then | |
136 | c=true | |
137 | if not e then | |
138 | H"luasec not found" | |
139 | c=false | |
140 | end | |
141 | if A(t)~="table"then | |
142 | H"server.lua: wrong server sslctx" | |
143 | c=false | |
144 | end | |
145 | local o; | |
146 | o,m=e(t) | |
147 | if not o then | |
148 | m=m or"wrong sslctx parameters" | |
149 | local a; | |
150 | a=m:match("^error loading (.-) %("); | |
151 | if a then | |
152 | if a=="private key"then | |
153 | a=t.key or"your private key"; | |
154 | elseif a=="certificate"then | |
155 | a=t.certificate or"your certificate file"; | |
156 | end | |
157 | local e=m:match("%((.+)%)$")or"some reason"; | |
158 | if e=="Permission denied"then | |
159 | e="Check that the permissions allow Prosody to read this file."; | |
160 | elseif e=="No such file or directory"then | |
161 | e="Check that the path is correct, and the file exists."; | |
162 | elseif e=="system lib"then | |
163 | e="Previous error (see logs), or other system error."; | |
164 | else | |
165 | e="Reason: "..h(e or"unknown"):lower(); | |
166 | end | |
167 | w("error","SSL/TLS: Failed to load %s: %s",a,e); | |
168 | else | |
169 | w("error","SSL/TLS: Error initialising for port %d: %s",u,m); | |
170 | end | |
171 | c=false | |
172 | end | |
173 | t=o; | |
174 | end | |
175 | if not c then | |
176 | t=false; | |
177 | if v then | |
178 | w("error","Failed to listen on port %d due to SSL/TLS to SSL/TLS initialisation errors (see logs)",u) | |
179 | return nil,"Cannot start ssl, see log for details" | |
180 | end | |
181 | end | |
182 | local m=l.accept | |
183 | local e={} | |
184 | e.shutdown=function()end | |
185 | e.ssl=function() | |
186 | return c | |
187 | end | |
188 | e.sslctx=function() | |
189 | return t | |
190 | end | |
191 | e.remove=function() | |
192 | f=f-1 | |
193 | end | |
194 | e.close=function() | |
195 | for t,e in T(i)do | |
196 | if e.serverport==u then | |
197 | e.disconnect(e,"server closed") | |
198 | e:close(true) | |
199 | end | |
200 | end | |
201 | l:close() | |
202 | o=d(r,l,o) | |
203 | a=d(s,l,a) | |
204 | i[l]=nil | |
205 | e=nil | |
206 | l=nil | |
207 | n"server.lua: closed server handler and removed sockets from list" | |
208 | end | |
209 | e.ip=function() | |
210 | return k | |
211 | end | |
212 | e.serverport=function() | |
213 | return u | |
214 | end | |
215 | e.socket=function() | |
216 | return l | |
217 | end | |
218 | e.readbuffer=function() | |
219 | if f>p then | |
220 | n("server.lua: refused new client connection: server full") | |
221 | return false | |
222 | end | |
223 | local a,s=m(l) | |
224 | if a then | |
225 | local i,o=a:getpeername() | |
226 | a:settimeout(0) | |
227 | local e,a,t=D(e,y,a,i,u,o,b,t,v) | |
228 | if t then | |
229 | return false | |
230 | end | |
231 | f=f+1 | |
232 | n("server.lua: accepted new client connection from ",h(i),":",h(o)," to ",h(u)) | |
233 | return g(e) | |
234 | elseif s then | |
235 | n("server.lua: error with new client connection: ",h(s)) | |
236 | return false | |
237 | end | |
238 | end | |
239 | return e | |
240 | end | |
241 | D=function(M,e,t,I,Y,L,_,p,P) | |
242 | t:settimeout(0) | |
243 | local w | |
244 | local T | |
245 | local q | |
246 | local v | |
247 | local O=e.onincoming | |
248 | local F=e.status | |
249 | local g=e.ondisconnect | |
250 | local y={} | |
251 | local m=0 | |
252 | local C | |
253 | local A | |
254 | local D | |
255 | local l=0 | |
256 | local j=false | |
257 | local E=false | |
258 | local H,R=0,0 | |
259 | local z=z | |
260 | local x=x | |
261 | local e=y | |
262 | e.dispatch=function() | |
263 | return O | |
264 | end | |
265 | e.disconnect=function() | |
266 | return g | |
267 | end | |
268 | e.setlistener=function(a,t) | |
269 | O=t.onincoming | |
270 | g=t.ondisconnect | |
271 | end | |
272 | e.getstats=function() | |
273 | return R,H | |
274 | end | |
275 | e.ssl=function() | |
276 | return v | |
277 | end | |
278 | e.sslctx=function() | |
279 | return p | |
280 | end | |
281 | e.send=function(n,i,o,a) | |
282 | return w(t,i,o,a) | |
283 | end | |
284 | e.receive=function(a,o) | |
285 | return T(t,a,o) | |
286 | end | |
287 | e.shutdown=function(a) | |
288 | return q(t,a) | |
289 | end | |
290 | e.close=function(u,h) | |
291 | if not e then return true;end | |
292 | a=d(s,t,a) | |
293 | b[e]=nil | |
294 | if m~=0 then | |
295 | if not(h or A)then | |
296 | e.sendbuffer() | |
297 | if m~=0 then | |
298 | if e then | |
299 | e.write=nil | |
300 | end | |
301 | C=true | |
302 | return false | |
303 | end | |
304 | else | |
305 | w(t,te(y,"",1,m),1,l) | |
306 | end | |
307 | end | |
308 | if t then | |
309 | c=q and q(t) | |
310 | t:close() | |
311 | o=d(r,t,o) | |
312 | i[t]=nil | |
313 | t=nil | |
314 | else | |
315 | n"server.lua: socket already closed" | |
316 | end | |
317 | if e then | |
318 | f[e]=nil | |
319 | k[e]=nil | |
320 | e=nil | |
321 | end | |
322 | if M then | |
323 | M.remove() | |
324 | end | |
325 | n"server.lua: closed client handler and removed socket from list" | |
326 | return true | |
327 | end | |
328 | e.ip=function() | |
329 | return I | |
330 | end | |
331 | e.serverport=function() | |
332 | return Y | |
333 | end | |
334 | e.clientport=function() | |
335 | return L | |
336 | end | |
337 | local k=function(i,a) | |
338 | l=l+B(a) | |
339 | if l>z then | |
340 | k[e]="send buffer exceeded" | |
341 | e.write=W | |
342 | return false | |
343 | elseif t and not r[t]then | |
344 | o=addsocket(r,t,o) | |
345 | end | |
346 | m=m+1 | |
347 | y[m]=a | |
348 | if e then | |
349 | f[e]=f[e]or u | |
350 | end | |
351 | return true | |
352 | end | |
353 | e.write=k | |
354 | e.bufferqueue=function(t) | |
355 | return y | |
356 | end | |
357 | e.socket=function(a) | |
358 | return t | |
359 | end | |
360 | e.pattern=function(a,t) | |
361 | _=t or _ | |
362 | return _ | |
363 | end | |
364 | e.set_send=function(a,t) | |
365 | w=t or w | |
366 | return w | |
367 | end | |
368 | e.bufferlen=function(o,t,a) | |
369 | z=a or z | |
370 | x=t or x | |
371 | return l,x,z | |
372 | end | |
373 | e.lock_read=function(i,o) | |
374 | if o==true then | |
375 | local o=a | |
376 | a=d(s,t,a) | |
377 | b[e]=nil | |
378 | if a~=o then | |
379 | j=true | |
380 | end | |
381 | elseif o==false then | |
382 | if j then | |
383 | j=false | |
384 | a=addsocket(s,t,a) | |
385 | b[e]=u | |
386 | end | |
387 | end | |
388 | return j | |
389 | end | |
390 | e.lock=function(i,a) | |
391 | e.lock_read(a) | |
392 | if a==true then | |
393 | e.write=W | |
394 | local a=o | |
395 | o=d(r,t,o) | |
396 | f[e]=nil | |
397 | if o~=a then | |
398 | E=true | |
399 | end | |
400 | elseif a==false then | |
401 | e.write=k | |
402 | if E then | |
403 | E=false | |
404 | k("") | |
405 | end | |
406 | end | |
407 | return j,E | |
408 | end | |
409 | local b=function() | |
410 | local o,t,a=T(t,_) | |
411 | if not t or(t=="wantread"or t=="timeout")or B(a)>0 then | |
412 | local o=o or a or"" | |
413 | local a=B(o) | |
414 | if a>x then | |
415 | g(e,"receive buffer exceeded") | |
416 | e.close(true) | |
417 | return false | |
418 | end | |
419 | local a=a*ie | |
420 | R=R+a | |
421 | S=S+a | |
422 | b[e]=u | |
423 | return O(e,o,t) | |
424 | else | |
425 | n("server.lua: client ",h(I),":",h(L)," read error: ",h(t)) | |
426 | A=true | |
427 | g(e,t) | |
428 | c=e and e.close() | |
429 | return false | |
430 | end | |
431 | end | |
432 | local f=function() | |
433 | local p,a,i,s,v; | |
434 | local v; | |
435 | if t then | |
436 | s=te(y,"",1,m) | |
437 | p,a,i=w(t,s,1,l) | |
438 | v=(p or i or 0)*ie | |
439 | H=H+v | |
440 | U=U+v | |
441 | c=N and J(y) | |
442 | else | |
443 | p,a,v=false,"closed",0; | |
444 | end | |
445 | if p then | |
446 | m=0 | |
447 | l=0 | |
448 | o=d(r,t,o) | |
449 | c=D and e:starttls(true) | |
450 | f[e]=nil | |
451 | c=C and e.close() | |
452 | return true | |
453 | elseif i and(a=="timeout"or a=="wantwrite")then | |
454 | s=de(s,i+1,l) | |
455 | y[1]=s | |
456 | m=1 | |
457 | l=l-i | |
458 | f[e]=u | |
459 | return true | |
460 | else | |
461 | n("server.lua: client ",h(I),":",h(L)," write error: ",h(a)) | |
462 | A=true | |
463 | g(e,a) | |
464 | c=e and e.close() | |
465 | return false | |
466 | end | |
467 | end | |
468 | local l; | |
469 | function e.set_sslctx(i,t) | |
470 | v=true | |
471 | p=t; | |
472 | local u | |
473 | local m | |
474 | l=ue(function(t) | |
475 | local i | |
476 | for l=1,_maxsslhandshake do | |
477 | o=(u and d(r,t,o))or o | |
478 | a=(m and d(s,t,a))or a | |
479 | m,u=nil,nil | |
480 | c,i=t:dohandshake() | |
481 | if not i then | |
482 | n("server.lua: ssl handshake done") | |
483 | e.readbuffer=b | |
484 | e.sendbuffer=f | |
485 | c=F and F(e,"ssl-handshake-complete") | |
486 | a=addsocket(s,t,a) | |
487 | return true | |
488 | else | |
489 | n("server.lua: error during ssl handshake: ",h(i)) | |
490 | if i=="wantwrite"and not u then | |
491 | o=addsocket(r,t,o) | |
492 | u=true | |
493 | elseif i=="wantread"and not m then | |
494 | a=addsocket(s,t,a) | |
495 | m=true | |
496 | else | |
497 | break; | |
498 | end | |
499 | le() | |
500 | end | |
501 | end | |
502 | g(e,"ssl handshake failed") | |
503 | c=e and e:close(true) | |
504 | return false | |
505 | end | |
506 | ) | |
507 | end | |
508 | if p then | |
509 | e:set_sslctx(p); | |
510 | if P then | |
511 | local a | |
512 | t,a=ee(t,p) | |
513 | if a then | |
514 | n("server.lua: ssl error: ",h(a)) | |
515 | return nil,nil,a | |
516 | end | |
517 | t:settimeout(0) | |
518 | e.readbuffer=l | |
519 | e.sendbuffer=l | |
520 | l(t) | |
521 | if not t then | |
522 | return nil,nil,"ssl handshake failed"; | |
523 | end | |
524 | else | |
525 | v=false | |
526 | e.starttls=function(c,u) | |
527 | if not u then | |
528 | D=true | |
529 | return | |
530 | end | |
531 | local c,u=t | |
532 | t,u=ee(t,p) | |
533 | if u then | |
534 | n("server.lua: error while starting tls on client: ",h(u)) | |
535 | return nil,u | |
536 | end | |
537 | t:settimeout(0) | |
538 | w=t.send | |
539 | T=t.receive | |
540 | q=G | |
541 | i[t]=e | |
542 | a=addsocket(s,t,a) | |
543 | a=d(s,c,a) | |
544 | o=d(r,c,o) | |
545 | i[c]=nil | |
546 | e.starttls=nil | |
547 | D=nil | |
548 | v=true | |
549 | e.readbuffer=l | |
550 | e.sendbuffer=l | |
551 | l(t) | |
552 | end | |
553 | e.readbuffer=b | |
554 | e.sendbuffer=f | |
555 | end | |
556 | else | |
557 | v=false | |
558 | e.readbuffer=b | |
559 | e.sendbuffer=f | |
560 | end | |
561 | w=t.send | |
562 | T=t.receive | |
563 | q=(v and G)or t.shutdown | |
564 | i[t]=e | |
565 | a=addsocket(s,t,a) | |
566 | return e,t | |
567 | end | |
568 | G=function() | |
569 | end | |
570 | W=function() | |
571 | return false | |
572 | end | |
573 | addsocket=function(a,t,e) | |
574 | if not a[t]then | |
575 | e=e+1 | |
576 | a[e]=t | |
577 | a[t]=e | |
578 | end | |
579 | return e; | |
580 | end | |
581 | d=function(e,a,t) | |
582 | local o=e[a] | |
583 | if o then | |
584 | e[a]=nil | |
585 | local i=e[t] | |
586 | e[t]=nil | |
587 | if i~=a then | |
588 | e[i]=o | |
589 | e[o]=i | |
590 | end | |
591 | return t-1 | |
592 | end | |
593 | return t | |
594 | end | |
595 | P=function(e) | |
596 | o=d(r,e,o) | |
597 | a=d(s,e,a) | |
598 | i[e]=nil | |
599 | e:close() | |
600 | end | |
601 | re=function(o,e,d,u,r,l) | |
602 | local t | |
603 | if A(d)~="table"then | |
604 | t="invalid listener table" | |
605 | end | |
606 | if not A(e)=="number"or not(e>=0 and e<=65535)then | |
607 | t="invalid port" | |
608 | elseif p[e]then | |
609 | t="listeners on port '"..e.."' already exist" | |
610 | elseif r and not I then | |
611 | t="luasec not found" | |
612 | end | |
613 | if t then | |
614 | H("server.lua, port ",e,": ",t) | |
615 | return nil,t | |
616 | end | |
617 | o=o or"*" | |
618 | local t,h=fe(o,e) | |
619 | if h then | |
620 | H("server.lua, port ",e,": ",h) | |
621 | return nil,h | |
622 | end | |
623 | local h,r=ae(d,t,o,e,u,r,g,l) | |
624 | if not h then | |
625 | t:close() | |
626 | return nil,r | |
627 | end | |
628 | t:settimeout(0) | |
629 | a=addsocket(s,t,a) | |
630 | p[e]=h | |
631 | i[t]=h | |
632 | n("server.lua: new server listener on '",o,":",e,"'") | |
633 | return h | |
634 | end | |
635 | se=function(e) | |
636 | return p[e]; | |
637 | end | |
638 | Q=function(e) | |
639 | local t=p[e] | |
640 | if not t then | |
641 | return nil,"no server found on port '"..h(e).."'" | |
642 | end | |
643 | t:close() | |
644 | p[e]=nil | |
645 | return true | |
646 | end | |
647 | ne=function() | |
648 | for t,e in T(i)do | |
649 | e:close() | |
650 | i[t]=nil | |
651 | end | |
652 | a=0 | |
653 | o=0 | |
654 | v=0 | |
655 | p={} | |
656 | s={} | |
657 | r={} | |
658 | C={} | |
659 | i={} | |
660 | end | |
661 | oe=function() | |
662 | return _,j,z,x,O,E,q,N,g,_maxsslhandshake | |
663 | end | |
664 | K=function(e) | |
665 | if A(e)~="table"then | |
666 | return nil,"invalid settings table" | |
667 | end | |
668 | _=tonumber(e.timeout)or _ | |
669 | j=tonumber(e.sleeptime)or j | |
670 | z=tonumber(e.maxsendlen)or z | |
671 | x=tonumber(e.maxreadlen)or x | |
672 | O=tonumber(e.checkinterval)or O | |
673 | E=tonumber(e.sendtimeout)or E | |
674 | q=tonumber(e.readtimeout)or q | |
675 | N=e.cleanqueue | |
676 | g=e._maxclientsperserver or g | |
677 | _maxsslhandshake=e._maxsslhandshake or _maxsslhandshake | |
678 | return true | |
679 | end | |
680 | Y=function(e) | |
681 | if A(e)~="function"then | |
682 | return nil,"invalid listener function" | |
683 | end | |
684 | v=v+1 | |
685 | C[v]=e | |
686 | return true | |
687 | end | |
688 | Z=function() | |
689 | return S,U,a,o,v | |
690 | end | |
691 | local e=true; | |
692 | setquitting=function(t) | |
693 | e=not t; | |
694 | return; | |
695 | end | |
696 | X=function() | |
697 | while e do | |
698 | local a,e,t=ce(s,r,_) | |
699 | for e,t in he(e)do | |
700 | local e=i[t] | |
701 | if e then | |
702 | e.sendbuffer() | |
703 | else | |
704 | P(t) | |
705 | n"server.lua: found no handler and closed socket (writelist)" | |
706 | end | |
707 | end | |
708 | for t,e in he(a)do | |
709 | local t=i[e] | |
710 | if t then | |
711 | t.readbuffer() | |
712 | else | |
713 | P(e) | |
714 | n"server.lua: found no handler and closed socket (readlist)" | |
715 | end | |
716 | end | |
717 | for e,t in T(k)do | |
718 | e.disconnect()(e,t) | |
719 | e:close(true) | |
720 | end | |
721 | J(k) | |
722 | u=V() | |
723 | if R(u-F)>=1 then | |
724 | for e=1,v do | |
725 | C[e](u) | |
726 | end | |
727 | F=u | |
728 | end | |
729 | me(j) | |
730 | end | |
731 | return"quitting" | |
732 | end | |
733 | local function s() | |
734 | return"select"; | |
735 | end | |
736 | local n=function(e,s,n,t,a,h,d) | |
737 | local t=D(nil,t,e,s,n,"clientport",a,h,d) | |
738 | i[e]=t | |
739 | o=addsocket(r,e,o) | |
740 | return t,e | |
741 | end | |
742 | local t=function(a,o,i,s,r,h) | |
743 | local t,e=L.tcp() | |
744 | if e then | |
745 | return nil,e | |
746 | end | |
747 | t:settimeout(0) | |
748 | c,e=t:connect(a,o) | |
749 | if e then | |
750 | local e=n(t,a,o,i) | |
751 | else | |
752 | D(nil,i,t,a,o,"clientport",s,r,h) | |
753 | end | |
754 | end | |
755 | l"setmetatable"(i,{__mode="k"}) | |
756 | l"setmetatable"(b,{__mode="k"}) | |
757 | l"setmetatable"(f,{__mode="k"}) | |
758 | F=V() | |
759 | M=V() | |
760 | Y(function() | |
761 | local e=R(u-M) | |
762 | if e>O then | |
763 | M=u | |
764 | for e,t in T(f)do | |
765 | if R(u-t)>E then | |
766 | e.disconnect()(e,"send timeout") | |
767 | e:close(true) | |
768 | end | |
769 | end | |
770 | for e,t in T(b)do | |
771 | if R(u-t)>q then | |
772 | e.disconnect()(e,"read timeout") | |
773 | e:close() | |
774 | end | |
775 | end | |
776 | end | |
777 | end | |
778 | ) | |
779 | return{ | |
780 | addclient=t, | |
781 | wrapclient=n, | |
782 | loop=X, | |
783 | stats=Z, | |
784 | closeall=ne, | |
785 | addtimer=Y, | |
786 | addserver=re, | |
787 | getserver=se, | |
788 | getsettings=oe, | |
789 | setquitting=setquitting, | |
790 | removeserver=Q, | |
791 | get_backend=s, | |
792 | changesettings=K, | |
793 | } | |
794 | end) | |
795 | package.preload['net.httpclient_listener']=(function(...) | |
796 | local a=require"util.logger".init("httpclient_listener"); | |
797 | local i=require"net.connlisteners".register; | |
798 | local e={}; | |
799 | local t={}; | |
800 | local t={default_port=80,default_mode="*a"}; | |
801 | function t.onincoming(t,o) | |
802 | local e=e[t]; | |
803 | if not e then | |
804 | a("warn","Received response from connection %s with no request attached!",tostring(t)); | |
805 | return; | |
806 | end | |
807 | if o and e.reader then | |
808 | e:reader(o); | |
809 | end | |
810 | end | |
811 | function t.ondisconnect(a,t) | |
812 | local t=e[a]; | |
813 | if t then | |
814 | t:reader(nil); | |
815 | end | |
816 | e[a]=nil; | |
817 | end | |
818 | function t.register_request(o,t) | |
819 | a("debug","Attaching request %s to connection %s",tostring(t.id or t),tostring(o)); | |
820 | e[o]=t; | |
821 | end | |
822 | i("httpclient",t); | |
823 | end) | |
824 | package.preload['net.connlisteners']=(function(...) | |
825 | local r=(CFG_SOURCEDIR or".").."/net/"; | |
826 | local h=require"net.server"; | |
827 | local o=require"util.logger".init("connlisteners"); | |
828 | local i=tostring; | |
829 | local s,n,a= | |
830 | dofile,pcall,error | |
831 | module"connlisteners" | |
832 | local e={}; | |
833 | function register(t,a) | |
834 | if e[t]and e[t]~=a then | |
835 | o("debug","Listener %s is already registered, not registering any more",t); | |
836 | return false; | |
837 | end | |
838 | e[t]=a; | |
839 | o("debug","Registered connection listener %s",t); | |
840 | return true; | |
841 | end | |
842 | function deregister(t) | |
843 | e[t]=nil; | |
844 | end | |
845 | function get(t) | |
846 | local a=e[t]; | |
847 | if not a then | |
848 | local s,n=n(s,r..t:gsub("[^%w%-]","_").."_listener.lua"); | |
849 | if not s then | |
850 | o("error","Error while loading listener '%s': %s",i(t),i(n)); | |
851 | return nil,n; | |
852 | end | |
853 | a=e[t]; | |
854 | end | |
855 | return a; | |
856 | end | |
857 | function start(o,e) | |
858 | local t,n=get(o); | |
859 | if not t then | |
860 | a("No such connection module: "..o..(n and(" ("..n..")")or""),0); | |
861 | end | |
862 | if e then | |
863 | if(e.type=="ssl"or e.type=="tls")and not e.ssl then | |
864 | a("No SSL context supplied for a "..i(e.type):upper().." connection!",0); | |
865 | elseif e.ssl and e.type=="tcp"then | |
866 | a("SSL context supplied for a TCP connection!",0); | |
867 | end | |
868 | end | |
869 | local i=(e and e.interface)or t.default_interface or"*"; | |
870 | local o=(e and e.port)or t.default_port or a("Can't start listener "..o.." because no port was specified, and it has no default port",0); | |
871 | local a=(e and e.mode)or t.default_mode or 1; | |
872 | local n=(e and e.ssl)or nil; | |
873 | local s=99999999; | |
874 | local e=e and e.type=="ssl"; | |
875 | return h.addserver(i,o,t,a,n,e); | |
876 | end | |
877 | return _M; | |
878 | end) | |
879 | package.preload['net.http']=(function(...) | |
880 | local b=require"socket" | |
881 | local v=require"mime" | |
882 | local y=require"socket.url" | |
883 | local p=require"net.server" | |
884 | local e=require"net.connlisteners".get; | |
885 | local d=e("httpclient")or error("No httpclient listener!"); | |
886 | local r,i=table.insert,table.concat; | |
887 | local s,u,c,m,f,l,t,a= | |
888 | tonumber,tostring,pairs,xpcall,select,debug.traceback,string.char,string.format; | |
889 | local n=require"util.logger".init("http"); | |
890 | local o=function()end | |
891 | module"http" | |
892 | function urlencode(e)return e and(e:gsub("%W",function(e)return a("%%%02x",e:byte());end));end | |
893 | function urldecode(e)return e and(e:gsub("%%(%x%x)",function(e)return t(s(e,16));end));end | |
894 | local function w(t,e) | |
895 | if t.method=="HEAD"then return nil end | |
896 | if e==204 or e==304 or e==301 then return nil end | |
897 | if e>=100 and e<200 then return nil end | |
898 | return 1 | |
899 | end | |
900 | local function h(e,t,a) | |
901 | if not t then | |
902 | if e.body then | |
903 | n("debug","Connection closed, but we have data, calling callback..."); | |
904 | e.callback(i(e.body),e.code,e); | |
905 | elseif e.state~="completed"then | |
906 | e.callback("connection-closed",0,e); | |
907 | end | |
908 | destroy_request(e); | |
909 | e.body=nil; | |
910 | e.state="completed"; | |
911 | return; | |
912 | end | |
913 | if e.state=="body"and e.state~="completed"then | |
914 | o("Reading body...") | |
915 | if not e.body then e.body={};e.havebodylength,e.bodylength=0,s(e.responseheaders["content-length"]);end | |
916 | if a then | |
917 | t=t:sub(a,-1) | |
918 | end | |
919 | r(e.body,t); | |
920 | if e.bodylength then | |
921 | e.havebodylength=e.havebodylength+#t; | |
922 | if e.havebodylength>=e.bodylength then | |
923 | n("debug","Have full body, calling callback"); | |
924 | if e.callback then | |
925 | e.callback(i(e.body),e.code,e); | |
926 | end | |
927 | e.body=nil; | |
928 | e.state="completed"; | |
929 | else | |
930 | o("","Have "..e.havebodylength.." bytes out of "..e.bodylength); | |
931 | end | |
932 | end | |
933 | elseif e.state=="headers"then | |
934 | o("Reading headers...") | |
935 | local i=a; | |
936 | local n=e.responseheaders or{}; | |
937 | for t in t:sub(a,-1):gmatch("(.-)\r\n")do | |
938 | a=a+#t+2; | |
939 | local a,i=t:match("(%S+): (.+)"); | |
940 | if a and i then | |
941 | n[a:lower()]=i; | |
942 | o("Header: "..a:lower().." = "..i); | |
943 | elseif#t==0 then | |
944 | e.responseheaders=n; | |
945 | break; | |
946 | else | |
947 | o("Unhandled header line: "..t); | |
948 | end | |
949 | end | |
950 | e.state="body"; | |
951 | if#t>a then | |
952 | return h(e,t,a); | |
953 | end | |
954 | elseif e.state=="status"then | |
955 | o("Reading status...") | |
956 | local i,a,n,o=t:match("^HTTP/(%S+) (%d+) (.-)\r\n()",a); | |
957 | a=s(a); | |
958 | if not a then | |
959 | return e.callback("invalid-status-line",0,e); | |
960 | end | |
961 | e.code,e.responseversion=a,i; | |
962 | if e.onlystatus or not w(e,a)then | |
963 | if e.callback then | |
964 | e.callback(nil,a,e); | |
965 | end | |
966 | destroy_request(e); | |
967 | return; | |
968 | end | |
969 | e.state="headers"; | |
970 | if#t>o then | |
971 | return h(e,t,o); | |
972 | end | |
973 | end | |
974 | end | |
975 | local function w(e)n("error","Traceback[http]: %s: %s",u(e),l());end | |
976 | function request(e,a,s) | |
977 | local e=y.parse(e); | |
978 | if not(e and e.host)then | |
979 | s(nil,0,e); | |
980 | return nil,"invalid-url"; | |
981 | end | |
982 | if not e.path then | |
983 | e.path="/"; | |
984 | end | |
985 | local l,o; | |
986 | local t={["Host"]=e.host,["User-Agent"]="Prosody XMPP Server"} | |
987 | if e.userinfo then | |
988 | t["Authorization"]="Basic "..v.b64(e.userinfo); | |
989 | end | |
990 | if a then | |
991 | l=a.headers; | |
992 | e.onlystatus=a.onlystatus; | |
993 | o=a.body; | |
994 | if o then | |
995 | e.method="POST "; | |
996 | t["Content-Length"]=u(#o); | |
997 | t["Content-Type"]="application/x-www-form-urlencoded"; | |
998 | end | |
999 | if a.method then e.method=a.method;end | |
1000 | end | |
1001 | e.handler,e.conn=p.wrapclient(b.tcp(),e.host,e.port or 80,d,"*a"); | |
1002 | e.write=function(...)return e.handler:write(...);end | |
1003 | e.conn:settimeout(0); | |
1004 | local u,a=e.conn:connect(e.host,e.port or 80); | |
1005 | if not u and a~="timeout"then | |
1006 | s(nil,0,e); | |
1007 | return nil,a; | |
1008 | end | |
1009 | local a={e.method or"GET"," ",e.path," HTTP/1.1\r\n"}; | |
1010 | if e.query then | |
1011 | r(a,4,"?"); | |
1012 | r(a,5,e.query); | |
1013 | end | |
1014 | e.write(i(a)); | |
1015 | local a={[2]=": ",[4]="\r\n"}; | |
1016 | if l then | |
1017 | for o,n in c(l)do | |
1018 | a[1],a[3]=o,n; | |
1019 | e.write(i(a)); | |
1020 | t[o]=nil; | |
1021 | end | |
1022 | end | |
1023 | for o,n in c(t)do | |
1024 | a[1],a[3]=o,n; | |
1025 | e.write(i(a)); | |
1026 | t[o]=nil; | |
1027 | end | |
1028 | e.write("\r\n"); | |
1029 | if o then | |
1030 | e.write(o); | |
1031 | end | |
1032 | e.callback=function(a,t,o)n("debug","Calling callback, status %s",t or"---");return f(2,m(function()return s(a,t,o)end,w));end | |
1033 | e.reader=h; | |
1034 | e.state="status"; | |
1035 | d.register_request(e.handler,e); | |
1036 | return e; | |
1037 | end | |
1038 | function destroy_request(e) | |
1039 | if e.conn then | |
1040 | e.handler.close() | |
1041 | d.ondisconnect(e.conn,"closed"); | |
1042 | end | |
1043 | end | |
1044 | _M.urlencode=urlencode; | |
1045 | return _M; | |
1046 | end) | |
1047 | package.preload['util.timer']=(function(...) | |
1048 | local h=require"net.server".addtimer; | |
1049 | local a=require"net.server".event; | |
1050 | local d=require"net.server".event_base; | |
1051 | local s=os.time; | |
1052 | local n=table.insert; | |
1053 | local e=table.remove; | |
1054 | local e,i=ipairs,pairs; | |
1055 | local r=type; | |
1056 | local o={}; | |
1057 | local t={}; | |
1058 | module"timer" | |
1059 | local e; | |
1060 | if not a then | |
1061 | function e(e,a) | |
1062 | local o=s(); | |
1063 | e=e+o; | |
1064 | if e>=o then | |
1065 | n(t,{e,a}); | |
1066 | else | |
1067 | a(); | |
1068 | end | |
1069 | end | |
1070 | h(function() | |
1071 | local s=s(); | |
1072 | if#t>0 then | |
1073 | for a,e in i(t)do | |
1074 | n(o,e); | |
1075 | end | |
1076 | t={}; | |
1077 | end | |
1078 | for i,t in i(o)do | |
1079 | local t,a=t[1],t[2]; | |
1080 | if t<=s then | |
1081 | o[i]=nil; | |
1082 | local t=a(s); | |
1083 | if r(t)=="number"then e(t,a);end | |
1084 | end | |
1085 | end | |
1086 | end); | |
1087 | else | |
1088 | local t=(a.core and a.core.LEAVE)or-1; | |
1089 | function e(a,e) | |
1090 | d:addevent(nil,0,function() | |
1091 | local e=e(); | |
1092 | if e then | |
1093 | return 0,e; | |
1094 | else | |
1095 | return t; | |
1096 | end | |
1097 | end | |
1098 | ,a); | |
1099 | end | |
1100 | end | |
1101 | add_task=e; | |
1102 | return _M; | |
1103 | end) | |
1104 | package.preload['multihttp']=(function(...) | |
1105 | local s=require"net.http"; | |
1106 | local o=require"net.server"; | |
1107 | local i=require"util.timer"; | |
1108 | local n,h,r,d= | |
1109 | pairs,ipairs,type,setmetatable; | |
1110 | module"multihttp" | |
1111 | __index=_M; | |
1112 | function set_callback(t,e) | |
1113 | t.callback=e; | |
1114 | end | |
1115 | function set_progress_callback(e,a,t) | |
1116 | t=t or 1; | |
1117 | e.progress_callback=a; | |
1118 | i.add_task(t,function() | |
1119 | if e.progress_callback then | |
1120 | e.progress_callback(e); | |
1121 | if e.progress_callback then | |
1122 | return t; | |
1123 | end | |
1124 | end | |
1125 | end); | |
1126 | end | |
1127 | function add_url(t,e) | |
1128 | t.urls[e]=true; | |
1129 | end | |
1130 | function remove_url(t,e) | |
1131 | t.urls[e]=nil; | |
1132 | end | |
1133 | function download(e,i) | |
1134 | e.status="downloading"; | |
1135 | local t=0; | |
1136 | for a in n(e.urls)do | |
1137 | t=t+1; | |
1138 | e.urls[a]= | |
1139 | s.request(a,nil,function(n,t,s) | |
1140 | if e.callback then | |
1141 | e.downloading_count=e.downloading_count-1; | |
1142 | e.callback(a,t,n,s); | |
1143 | if e.downloading_count==0 and i then | |
1144 | o.setquitting(true); | |
1145 | end | |
1146 | end | |
1147 | end); | |
1148 | end | |
1149 | e.download_count=t; | |
1150 | e.downloading_count=t; | |
1151 | if i then | |
1152 | o.loop(); | |
1153 | o.setquitting(false); | |
1154 | end | |
1155 | return t; | |
1156 | end | |
1157 | function progress(e) | |
1158 | local a={total={}}; | |
1159 | for o,t in n(e.urls)do | |
1160 | local e={}; | |
1161 | e.bytes_downloaded=t.havebodylength; | |
1162 | e.bytes_total=t.bodylength; | |
1163 | if e.bytes_total then | |
1164 | e.percent=100/(e.bytes_total/e.bytes_downloaded); | |
1165 | end | |
1166 | a[o]=e; | |
1167 | end | |
1168 | return a; | |
1169 | end | |
1170 | function new(t,e) | |
1171 | local t={callback=t,urls={}}; | |
1172 | if r(e)=="table"then | |
1173 | for a,e in h(e)do | |
1174 | t.urls[e]=true; | |
1175 | end | |
1176 | end | |
1177 | return d(t,_M); | |
1178 | end | |
1179 | return _M; | |
1180 | end) | |
1181 | require"net.connlisteners" | |
1182 | require"net.httpclient_listener" | |
1183 | return require"net.http"; |