aboutsummaryrefslogtreecommitdiff
path: root/etc
diff options
context:
space:
mode:
Diffstat (limited to 'etc')
-rw-r--r--etc/check-links-nb.lua277
-rw-r--r--etc/check-links.lua2
-rw-r--r--etc/check-memory.lua4
-rw-r--r--etc/get.lua2
4 files changed, 4 insertions, 281 deletions
diff --git a/etc/check-links-nb.lua b/etc/check-links-nb.lua
deleted file mode 100644
index c379e9a..0000000
--- a/etc/check-links-nb.lua
+++ /dev/null
@@ -1,277 +0,0 @@
1-----------------------------------------------------------------------------
2-- Little program that checks links in HTML files, using coroutines and
3-- non-blocking I/O. Thus, faster than simpler version of same program
4-- LuaSocket sample files
5-- Author: Diego Nehab
6-- RCS ID: $$
7-----------------------------------------------------------------------------
8local socket = require("socket")
9
10TIMEOUT = 10
11
12-- we need to yield across calls to protect, so we can't use pcall
13-- we borrow and simplify code from coxpcall to reimplement socket.protect
14-- before loading http
15function socket.protect(f)
16 return function(...)
17 local co = coroutine.create(f)
18 while true do
19 local results = {coroutine.resume(co, unpack(arg))}
20 local status = results[1]
21 table.remove(results, 1)
22 if not status then
23 return nil, results[1][1]
24 end
25 if coroutine.status(co) == "suspended" then
26 arg = {coroutine.yield(unpack(results))}
27 else
28 return unpack(results)
29 end
30 end
31 end
32end
33
34local http = require("socket.http")
35local url = require("socket.url")
36
37-- creates a new set data structure
38function newset()
39 local reverse = {}
40 local set = {}
41 return setmetatable(set, {__index = {
42 insert = function(set, value)
43 if not reverse[value] then
44 table.insert(set, value)
45 reverse[value] = table.getn(set)
46 end
47 end,
48 remove = function(set, value)
49 local index = reverse[value]
50 if index then
51 reverse[value] = nil
52 local top = table.remove(set)
53 if top ~= value then
54 reverse[top] = index
55 set[index] = top
56 end
57 end
58 end
59 }})
60end
61
62local context = {}
63local sending = newset()
64local receiving = newset()
65local nthreads = 0
66
67-- socket.tcp() replacement for non-blocking I/O
68-- implements enough functionality to be used with http.request
69-- in Lua 5.1, we have coroutine.running to simplify things...
70function newcreate(thread)
71 return function()
72 -- try to create underlying socket
73 local tcp, error = socket.tcp()
74 if not tcp then return nil, error end
75 -- put it in non-blocking mode right away
76 tcp:settimeout(0)
77 local trap = {
78 -- we ignore settimeout to preserve our 0 timeout
79 settimeout = function(self, mode, value)
80 return 1
81 end,
82 -- send in non-blocking mode and yield on timeout
83 send = function(self, data, first, last)
84 first = (first or 1) - 1
85 local result, error
86 while true do
87 -- tell dispatcher we want to keep sending before we
88 -- yield control
89 sending:insert(tcp)
90 -- return control to dispatcher
91 -- if upon return the dispatcher tells us we timed out,
92 -- return an error to whoever called us
93 if coroutine.yield() == "timeout" then
94 return nil, "timeout"
95 end
96 -- mark time we started waiting
97 context[tcp].last = socket.gettime()
98 -- try sending
99 result, error, first = tcp:send(data, first+1, last)
100 -- if we are done, or there was an unexpected error,
101 -- break away from loop
102 if error ~= "timeout" then return result, error, first end
103 end
104 end,
105 -- receive in non-blocking mode and yield on timeout
106 receive = function(self, pattern)
107 local error, partial = "timeout", ""
108 local value
109 while true do
110 -- tell dispatcher we want to keep receiving before we
111 -- yield control
112 receiving:insert(tcp)
113 -- return control to dispatcher
114 -- if upon return the dispatcher tells us we timed out,
115 -- return an error to whoever called us
116 if coroutine.yield() == "timeout" then
117 return nil, "timeout"
118 end
119 -- mark time we started waiting
120 context[tcp].last = socket.gettime()
121 -- try receiving
122 value, error, partial = tcp:receive(pattern, partial)
123 -- if we are done, or there was an unexpected error,
124 -- break away from loop
125 if error ~= "timeout" then return value, error, partial end
126 end
127 end,
128 -- connect in non-blocking mode and yield on timeout
129 connect = function(self, host, port)
130 local result, error = tcp:connect(host, port)
131 -- mark time we started waiting
132 context[tcp].last = socket.gettime()
133 if error == "timeout" then
134 -- tell dispatcher we will be able to write uppon connection
135 sending:insert(tcp)
136 -- return control to dispatcher
137 -- if upon return the dispatcher tells us we have a
138 -- timeout, just abort
139 if coroutine.yield() == "timeout" then
140 return nil, "timeout"
141 end
142 -- when we come back, check if connection was successful
143 result, error = tcp:connect(host, port)
144 if result or error == "already connected" then return 1
145 else return nil, "non-blocking connect failed" end
146 else return result, error end
147 end,
148 close = function(self)
149 context[tcp] = nil
150 return tcp:close()
151 end
152 }
153 -- add newly created socket to context
154 context[tcp] = {
155 thread = thread,
156 trap = trap
157 }
158 return trap
159 end
160end
161
162-- get the status of a URL, non-blocking
163function getstatus(link)
164 local parsed = url.parse(link, {scheme = "file"})
165 if parsed.scheme == "http" then
166 local thread = coroutine.create(function(thread, link)
167 local r, c, h, s = http.request{
168 method = "HEAD",
169 url = link,
170 create = newcreate(thread)
171 }
172 if c == 200 then io.write('\t', link, '\n')
173 else io.write('\t', link, ': ', c, '\n') end
174 nthreads = nthreads - 1
175 end)
176 nthreads = nthreads + 1
177 assert(coroutine.resume(thread, thread, link))
178 end
179end
180
181-- dispatch all threads until we are done
182function dispatch()
183 while nthreads > 0 do
184 -- check which sockets are interesting and act on them
185 local readable, writable = socket.select(receiving, sending, 1)
186 -- for all readable connections, resume their threads
187 for _, who in ipairs(readable) do
188 if context[who] then
189 receiving:remove(who)
190 assert(coroutine.resume(context[who].thread))
191 end
192 end
193 -- for all writable connections, do the same
194 for _, who in ipairs(writable) do
195 if context[who] then
196 sending:remove(who)
197 assert(coroutine.resume(context[who].thread))
198 end
199 end
200 -- politely ask replacement I/O functions in idle threads to
201 -- return reporting a timeout
202 local now = socket.gettime()
203 for who, data in pairs(context) do
204 if data.last and now - data.last > TIMEOUT then
205 sending:remove(who)
206 receiving:remove(who)
207 assert(coroutine.resume(context[who].thread, "timeout"))
208 end
209 end
210 end
211end
212
213function readfile(path)
214 path = url.unescape(path)
215 local file, error = io.open(path, "r")
216 if file then
217 local body = file:read("*a")
218 file:close()
219 return body
220 else return nil, error end
221end
222
223function load(u)
224 local parsed = url.parse(u, { scheme = "file" })
225 local body, headers, code, error
226 local base = u
227 if parsed.scheme == "http" then
228 body, code, headers = http.request(u)
229 if code == 200 then
230 -- if there was a redirect, update base to reflect it
231 base = headers.location or base
232 end
233 if not body then
234 error = code
235 end
236 elseif parsed.scheme == "file" then
237 body, error = readfile(parsed.path)
238 else error = string.format("unhandled scheme '%s'", parsed.scheme) end
239 return base, body, error
240end
241
242function getlinks(body, base)
243 -- get rid of comments
244 body = string.gsub(body, "%<%!%-%-.-%-%-%>", "")
245 local links = {}
246 -- extract links
247 body = string.gsub(body, '[Hh][Rr][Ee][Ff]%s*=%s*"([^"]*)"', function(href)
248 table.insert(links, url.absolute(base, href))
249 end)
250 body = string.gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*'([^']*)'", function(href)
251 table.insert(links, url.absolute(base, href))
252 end)
253 string.gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*(.-)>", function(href)
254 table.insert(links, url.absolute(base, href))
255 end)
256 return links
257end
258
259function checklinks(address)
260 local base, body, error = load(address)
261 if not body then print(error) return end
262 print("Checking ", base)
263 local links = getlinks(body, base)
264 for _, link in ipairs(links) do
265 getstatus(link)
266 end
267end
268
269arg = arg or {}
270if table.getn(arg) < 1 then
271 print("Usage:\n luasocket check-links.lua {<url>}")
272 exit()
273end
274for _, address in ipairs(arg) do
275 checklinks(url.absolute("file:", address))
276end
277dispatch()
diff --git a/etc/check-links.lua b/etc/check-links.lua
index 725cd2a..5c124a8 100644
--- a/etc/check-links.lua
+++ b/etc/check-links.lua
@@ -5,7 +5,7 @@
5-- Author: Diego Nehab 5-- Author: Diego Nehab
6-- RCS ID: $$ 6-- RCS ID: $$
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8local url = require("socket.url") 8local url = require("url")
9local dispatch = require("dispatch") 9local dispatch = require("dispatch")
10local http = require("socket.http") 10local http = require("socket.http")
11dispatch.TIMEOUT = 10 11dispatch.TIMEOUT = 10
diff --git a/etc/check-memory.lua b/etc/check-memory.lua
index 7892ba0..7bcdf67 100644
--- a/etc/check-memory.lua
+++ b/etc/check-memory.lua
@@ -7,9 +7,9 @@ function load(s)
7 print(s .. ":\t " .. (b-a) .. "k") 7 print(s .. ":\t " .. (b-a) .. "k")
8end 8end
9 9
10load("socket") 10load("url")
11load("socket.url")
12load("ltn12") 11load("ltn12")
12load("socket")
13load("mime") 13load("mime")
14load("socket.tp") 14load("socket.tp")
15load("socket.smtp") 15load("socket.smtp")
diff --git a/etc/get.lua b/etc/get.lua
index 0c95d54..bd5af28 100644
--- a/etc/get.lua
+++ b/etc/get.lua
@@ -7,7 +7,7 @@
7local socket = require("socket") 7local socket = require("socket")
8local http = require("socket.http") 8local http = require("socket.http")
9local ftp = require("socket.ftp") 9local ftp = require("socket.ftp")
10local url = require("socket.url") 10local url = require("url")
11local ltn12 = require("ltn12") 11local ltn12 = require("ltn12")
12 12
13-- formats a number of seconds into human readable form 13-- formats a number of seconds into human readable form