Commit 5507e9772c943e34ba4abac4e6afae978155824e
1 parent
9ce0336b
import luasocket
remdebug (but it is probably too slow to use) better stacktrace (elcugo) git-svn-id: http://svn.net-core.org/repos/t-engine4@27 51575b47-30f0-44d4-a5cc-537603b46e54
Showing
31 changed files
with
4585 additions
and
3 deletions
Too many changes to show.
To preserve performance only 31 of 31+ files are displayed.
game/thirdparty/ltn12.lua
0 → 100644
1 | +----------------------------------------------------------------------------- | |
2 | +-- LTN12 - Filters, sources, sinks and pumps. | |
3 | +-- LuaSocket toolkit. | |
4 | +-- Author: Diego Nehab | |
5 | +-- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $ | |
6 | +----------------------------------------------------------------------------- | |
7 | + | |
8 | +----------------------------------------------------------------------------- | |
9 | +-- Declare module | |
10 | +----------------------------------------------------------------------------- | |
11 | +local string = require("string") | |
12 | +local table = require("table") | |
13 | +local base = _G | |
14 | +module("ltn12") | |
15 | + | |
16 | +filter = {} | |
17 | +source = {} | |
18 | +sink = {} | |
19 | +pump = {} | |
20 | + | |
21 | +-- 2048 seems to be better in windows... | |
22 | +BLOCKSIZE = 2048 | |
23 | +_VERSION = "LTN12 1.0.1" | |
24 | + | |
25 | +----------------------------------------------------------------------------- | |
26 | +-- Filter stuff | |
27 | +----------------------------------------------------------------------------- | |
28 | +-- returns a high level filter that cycles a low-level filter | |
29 | +function filter.cycle(low, ctx, extra) | |
30 | + base.assert(low) | |
31 | + return function(chunk) | |
32 | + local ret | |
33 | + ret, ctx = low(ctx, chunk, extra) | |
34 | + return ret | |
35 | + end | |
36 | +end | |
37 | + | |
38 | +-- chains a bunch of filters together | |
39 | +-- (thanks to Wim Couwenberg) | |
40 | +function filter.chain(...) | |
41 | + local n = table.getn(arg) | |
42 | + local top, index = 1, 1 | |
43 | + local retry = "" | |
44 | + return function(chunk) | |
45 | + retry = chunk and retry | |
46 | + while true do | |
47 | + if index == top then | |
48 | + chunk = arg[index](chunk) | |
49 | + if chunk == "" or top == n then return chunk | |
50 | + elseif chunk then index = index + 1 | |
51 | + else | |
52 | + top = top+1 | |
53 | + index = top | |
54 | + end | |
55 | + else | |
56 | + chunk = arg[index](chunk or "") | |
57 | + if chunk == "" then | |
58 | + index = index - 1 | |
59 | + chunk = retry | |
60 | + elseif chunk then | |
61 | + if index == n then return chunk | |
62 | + else index = index + 1 end | |
63 | + else base.error("filter returned inappropriate nil") end | |
64 | + end | |
65 | + end | |
66 | + end | |
67 | +end | |
68 | + | |
69 | +----------------------------------------------------------------------------- | |
70 | +-- Source stuff | |
71 | +----------------------------------------------------------------------------- | |
72 | +-- create an empty source | |
73 | +local function empty() | |
74 | + return nil | |
75 | +end | |
76 | + | |
77 | +function source.empty() | |
78 | + return empty | |
79 | +end | |
80 | + | |
81 | +-- returns a source that just outputs an error | |
82 | +function source.error(err) | |
83 | + return function() | |
84 | + return nil, err | |
85 | + end | |
86 | +end | |
87 | + | |
88 | +-- creates a file source | |
89 | +function source.file(handle, io_err) | |
90 | + if handle then | |
91 | + return function() | |
92 | + local chunk = handle:read(BLOCKSIZE) | |
93 | + if not chunk then handle:close() end | |
94 | + return chunk | |
95 | + end | |
96 | + else return source.error(io_err or "unable to open file") end | |
97 | +end | |
98 | + | |
99 | +-- turns a fancy source into a simple source | |
100 | +function source.simplify(src) | |
101 | + base.assert(src) | |
102 | + return function() | |
103 | + local chunk, err_or_new = src() | |
104 | + src = err_or_new or src | |
105 | + if not chunk then return nil, err_or_new | |
106 | + else return chunk end | |
107 | + end | |
108 | +end | |
109 | + | |
110 | +-- creates string source | |
111 | +function source.string(s) | |
112 | + if s then | |
113 | + local i = 1 | |
114 | + return function() | |
115 | + local chunk = string.sub(s, i, i+BLOCKSIZE-1) | |
116 | + i = i + BLOCKSIZE | |
117 | + if chunk ~= "" then return chunk | |
118 | + else return nil end | |
119 | + end | |
120 | + else return source.empty() end | |
121 | +end | |
122 | + | |
123 | +-- creates rewindable source | |
124 | +function source.rewind(src) | |
125 | + base.assert(src) | |
126 | + local t = {} | |
127 | + return function(chunk) | |
128 | + if not chunk then | |
129 | + chunk = table.remove(t) | |
130 | + if not chunk then return src() | |
131 | + else return chunk end | |
132 | + else | |
133 | + table.insert(t, chunk) | |
134 | + end | |
135 | + end | |
136 | +end | |
137 | + | |
138 | +function source.chain(src, f) | |
139 | + base.assert(src and f) | |
140 | + local last_in, last_out = "", "" | |
141 | + local state = "feeding" | |
142 | + local err | |
143 | + return function() | |
144 | + if not last_out then | |
145 | + base.error('source is empty!', 2) | |
146 | + end | |
147 | + while true do | |
148 | + if state == "feeding" then | |
149 | + last_in, err = src() | |
150 | + if err then return nil, err end | |
151 | + last_out = f(last_in) | |
152 | + if not last_out then | |
153 | + if last_in then | |
154 | + base.error('filter returned inappropriate nil') | |
155 | + else | |
156 | + return nil | |
157 | + end | |
158 | + elseif last_out ~= "" then | |
159 | + state = "eating" | |
160 | + if last_in then last_in = "" end | |
161 | + return last_out | |
162 | + end | |
163 | + else | |
164 | + last_out = f(last_in) | |
165 | + if last_out == "" then | |
166 | + if last_in == "" then | |
167 | + state = "feeding" | |
168 | + else | |
169 | + base.error('filter returned ""') | |
170 | + end | |
171 | + elseif not last_out then | |
172 | + if last_in then | |
173 | + base.error('filter returned inappropriate nil') | |
174 | + else | |
175 | + return nil | |
176 | + end | |
177 | + else | |
178 | + return last_out | |
179 | + end | |
180 | + end | |
181 | + end | |
182 | + end | |
183 | +end | |
184 | + | |
185 | +-- creates a source that produces contents of several sources, one after the | |
186 | +-- other, as if they were concatenated | |
187 | +-- (thanks to Wim Couwenberg) | |
188 | +function source.cat(...) | |
189 | + local src = table.remove(arg, 1) | |
190 | + return function() | |
191 | + while src do | |
192 | + local chunk, err = src() | |
193 | + if chunk then return chunk end | |
194 | + if err then return nil, err end | |
195 | + src = table.remove(arg, 1) | |
196 | + end | |
197 | + end | |
198 | +end | |
199 | + | |
200 | +----------------------------------------------------------------------------- | |
201 | +-- Sink stuff | |
202 | +----------------------------------------------------------------------------- | |
203 | +-- creates a sink that stores into a table | |
204 | +function sink.table(t) | |
205 | + t = t or {} | |
206 | + local f = function(chunk, err) | |
207 | + if chunk then table.insert(t, chunk) end | |
208 | + return 1 | |
209 | + end | |
210 | + return f, t | |
211 | +end | |
212 | + | |
213 | +-- turns a fancy sink into a simple sink | |
214 | +function sink.simplify(snk) | |
215 | + base.assert(snk) | |
216 | + return function(chunk, err) | |
217 | + local ret, err_or_new = snk(chunk, err) | |
218 | + if not ret then return nil, err_or_new end | |
219 | + snk = err_or_new or snk | |
220 | + return 1 | |
221 | + end | |
222 | +end | |
223 | + | |
224 | +-- creates a file sink | |
225 | +function sink.file(handle, io_err) | |
226 | + if handle then | |
227 | + return function(chunk, err) | |
228 | + if not chunk then | |
229 | + handle:close() | |
230 | + return 1 | |
231 | + else return handle:write(chunk) end | |
232 | + end | |
233 | + else return sink.error(io_err or "unable to open file") end | |
234 | +end | |
235 | + | |
236 | +-- creates a sink that discards data | |
237 | +local function null() | |
238 | + return 1 | |
239 | +end | |
240 | + | |
241 | +function sink.null() | |
242 | + return null | |
243 | +end | |
244 | + | |
245 | +-- creates a sink that just returns an error | |
246 | +function sink.error(err) | |
247 | + return function() | |
248 | + return nil, err | |
249 | + end | |
250 | +end | |
251 | + | |
252 | +-- chains a sink with a filter | |
253 | +function sink.chain(f, snk) | |
254 | + base.assert(f and snk) | |
255 | + return function(chunk, err) | |
256 | + if chunk ~= "" then | |
257 | + local filtered = f(chunk) | |
258 | + local done = chunk and "" | |
259 | + while true do | |
260 | + local ret, snkerr = snk(filtered, err) | |
261 | + if not ret then return nil, snkerr end | |
262 | + if filtered == done then return 1 end | |
263 | + filtered = f(done) | |
264 | + end | |
265 | + else return 1 end | |
266 | + end | |
267 | +end | |
268 | + | |
269 | +----------------------------------------------------------------------------- | |
270 | +-- Pump stuff | |
271 | +----------------------------------------------------------------------------- | |
272 | +-- pumps one chunk from the source to the sink | |
273 | +function pump.step(src, snk) | |
274 | + local chunk, src_err = src() | |
275 | + local ret, snk_err = snk(chunk, src_err) | |
276 | + if chunk and ret then return 1 | |
277 | + else return nil, src_err or snk_err end | |
278 | +end | |
279 | + | |
280 | +-- pumps all data from a source to a sink, using a step function | |
281 | +function pump.all(src, snk, step) | |
282 | + base.assert(src and snk) | |
283 | + step = step or pump.step | |
284 | + while true do | |
285 | + local ret, err = step(src, snk) | |
286 | + if not ret then | |
287 | + if err then return nil, err | |
288 | + else return 1 end | |
289 | + end | |
290 | + end | |
291 | +end | |
292 | + | ... | ... |
game/thirdparty/mime.lua
0 → 100644
1 | +----------------------------------------------------------------------------- | |
2 | +-- MIME support for the Lua language. | |
3 | +-- Author: Diego Nehab | |
4 | +-- Conforming to RFCs 2045-2049 | |
5 | +-- RCS ID: $Id: mime.lua,v 1.29 2007/06/11 23:44:54 diego Exp $ | |
6 | +----------------------------------------------------------------------------- | |
7 | + | |
8 | +----------------------------------------------------------------------------- | |
9 | +-- Declare module and import dependencies | |
10 | +----------------------------------------------------------------------------- | |
11 | +local base = _G | |
12 | +local ltn12 = require("ltn12") | |
13 | +local mime = require("mime.core") | |
14 | +local io = require("io") | |
15 | +local string = require("string") | |
16 | +module("mime") | |
17 | + | |
18 | +-- encode, decode and wrap algorithm tables | |
19 | +encodet = {} | |
20 | +decodet = {} | |
21 | +wrapt = {} | |
22 | + | |
23 | +-- creates a function that chooses a filter by name from a given table | |
24 | +local function choose(table) | |
25 | + return function(name, opt1, opt2) | |
26 | + if base.type(name) ~= "string" then | |
27 | + name, opt1, opt2 = "default", name, opt1 | |
28 | + end | |
29 | + local f = table[name or "nil"] | |
30 | + if not f then | |
31 | + base.error("unknown key (" .. base.tostring(name) .. ")", 3) | |
32 | + else return f(opt1, opt2) end | |
33 | + end | |
34 | +end | |
35 | + | |
36 | +-- define the encoding filters | |
37 | +encodet['base64'] = function() | |
38 | + return ltn12.filter.cycle(b64, "") | |
39 | +end | |
40 | + | |
41 | +encodet['quoted-printable'] = function(mode) | |
42 | + return ltn12.filter.cycle(qp, "", | |
43 | + (mode == "binary") and "=0D=0A" or "\r\n") | |
44 | +end | |
45 | + | |
46 | +-- define the decoding filters | |
47 | +decodet['base64'] = function() | |
48 | + return ltn12.filter.cycle(unb64, "") | |
49 | +end | |
50 | + | |
51 | +decodet['quoted-printable'] = function() | |
52 | + return ltn12.filter.cycle(unqp, "") | |
53 | +end | |
54 | + | |
55 | +local function format(chunk) | |
56 | + if chunk then | |
57 | + if chunk == "" then return "''" | |
58 | + else return string.len(chunk) end | |
59 | + else return "nil" end | |
60 | +end | |
61 | + | |
62 | +-- define the line-wrap filters | |
63 | +wrapt['text'] = function(length) | |
64 | + length = length or 76 | |
65 | + return ltn12.filter.cycle(wrp, length, length) | |
66 | +end | |
67 | +wrapt['base64'] = wrapt['text'] | |
68 | +wrapt['default'] = wrapt['text'] | |
69 | + | |
70 | +wrapt['quoted-printable'] = function() | |
71 | + return ltn12.filter.cycle(qpwrp, 76, 76) | |
72 | +end | |
73 | + | |
74 | +-- function that choose the encoding, decoding or wrap algorithm | |
75 | +encode = choose(encodet) | |
76 | +decode = choose(decodet) | |
77 | +wrap = choose(wrapt) | |
78 | + | |
79 | +-- define the end-of-line normalization filter | |
80 | +function normalize(marker) | |
81 | + return ltn12.filter.cycle(eol, 0, marker) | |
82 | +end | |
83 | + | |
84 | +-- high level stuffing filter | |
85 | +function stuff() | |
86 | + return ltn12.filter.cycle(dot, 2) | |
87 | +end | ... | ... |
game/thirdparty/remdebug/engine.lua
0 → 100644
1 | +-- | |
2 | +-- RemDebug 1.0 Beta | |
3 | +-- Copyright Kepler Project 2005 (http://www.keplerproject.org/remdebug) | |
4 | +-- | |
5 | + | |
6 | +local socket = require"socket" | |
7 | +--local lfs = require"lfs" | |
8 | +local debug = require"debug" | |
9 | + | |
10 | +module("remdebug.engine", package.seeall) | |
11 | + | |
12 | +_COPYRIGHT = "2006 - Kepler Project" | |
13 | +_DESCRIPTION = "Remote Debugger for the Lua programming language" | |
14 | +_VERSION = "1.0" | |
15 | + | |
16 | +local coro_debugger | |
17 | +local events = { BREAK = 1, WATCH = 2 } | |
18 | +local breakpoints = {} | |
19 | +local watches = {} | |
20 | +local step_into = false | |
21 | +local step_over = false | |
22 | +local step_level = 0 | |
23 | +local stack_level = 0 | |
24 | + | |
25 | +local controller_host = "localhost" | |
26 | +local controller_port = 8171 | |
27 | + | |
28 | +local function set_breakpoint(file, line) | |
29 | + if not breakpoints[file] then | |
30 | + breakpoints[file] = {} | |
31 | + end | |
32 | + breakpoints[file][line] = true | |
33 | +end | |
34 | + | |
35 | +local function remove_breakpoint(file, line) | |
36 | + if breakpoints[file] then | |
37 | + breakpoints[file][line] = nil | |
38 | + end | |
39 | +end | |
40 | + | |
41 | +local function has_breakpoint(file, line) | |
42 | + return breakpoints[file] and breakpoints[file][line] | |
43 | +end | |
44 | + | |
45 | +local function restore_vars(vars) | |
46 | + if type(vars) ~= 'table' then return end | |
47 | + local func = debug.getinfo(3, "f").func | |
48 | + local i = 1 | |
49 | + local written_vars = {} | |
50 | + while true do | |
51 | + local name = debug.getlocal(3, i) | |
52 | + if not name then break end | |
53 | + debug.setlocal(3, i, vars[name]) | |
54 | + written_vars[name] = true | |
55 | + i = i + 1 | |
56 | + end | |
57 | + i = 1 | |
58 | + while true do | |
59 | + local name = debug.getupvalue(func, i) | |
60 | + if not name then break end | |
61 | + if not written_vars[name] then | |
62 | + debug.setupvalue(func, i, vars[name]) | |
63 | + written_vars[name] = true | |
64 | + end | |
65 | + i = i + 1 | |
66 | + end | |
67 | +end | |
68 | + | |
69 | +local function capture_vars() | |
70 | + local vars = {} | |
71 | + local func = debug.getinfo(3, "f").func | |
72 | + local i = 1 | |
73 | + while true do | |
74 | + local name, value = debug.getupvalue(func, i) | |
75 | + if not name then break end | |
76 | + vars[name] = value | |
77 | + i = i + 1 | |
78 | + end | |
79 | + i = 1 | |
80 | + while true do | |
81 | + local name, value = debug.getlocal(3, i) | |
82 | + if not name then break end | |
83 | + vars[name] = value | |
84 | + i = i + 1 | |
85 | + end | |
86 | + setmetatable(vars, { __index = getfenv(func), __newindex = getfenv(func) }) | |
87 | + return vars | |
88 | +end | |
89 | + | |
90 | +local function break_dir(path) | |
91 | + local paths = {} | |
92 | + path = string.gsub(path, "\\", "/") | |
93 | + for w in string.gfind(path, "[^\/]+") do | |
94 | + table.insert(paths, w) | |
95 | + end | |
96 | + return paths | |
97 | +end | |
98 | + | |
99 | +local function merge_paths(path1, path2) | |
100 | + local paths1 = break_dir(path1) | |
101 | + local paths2 = break_dir(path2) | |
102 | + for i, path in ipairs(paths2) do | |
103 | + if path == ".." then | |
104 | + table.remove(paths1, table.getn(paths1)) | |
105 | + elseif path ~= "." then | |
106 | + table.insert(paths1, path) | |
107 | + end | |
108 | + end | |
109 | + return table.concat(paths1, "/") | |
110 | +end | |
111 | + | |
112 | +local function debug_hook(event, line) | |
113 | + if event == "call" then | |
114 | + stack_level = stack_level + 1 | |
115 | + elseif event == "return" then | |
116 | + stack_level = stack_level - 1 | |
117 | + else | |
118 | + local file = debug.getinfo(2, "S").source | |
119 | + if string.find(file, "@") == 1 then | |
120 | + file = string.sub(file, 2) | |
121 | + end | |
122 | + file = merge_paths("/", file) | |
123 | + local vars = capture_vars() | |
124 | + table.foreach(watches, function (index, value) | |
125 | + setfenv(value, vars) | |
126 | + local status, res = pcall(value) | |
127 | + if status and res then | |
128 | + coroutine.resume(coro_debugger, events.WATCH, vars, file, line, index) | |
129 | + end | |
130 | + end) | |
131 | + if step_into or (step_over and stack_level <= step_level) or has_breakpoint(file, line) then | |
132 | + step_into = false | |
133 | + step_over = false | |
134 | + coroutine.resume(coro_debugger, events.BREAK, vars, file, line) | |
135 | + restore_vars(vars) | |
136 | + end | |
137 | + end | |
138 | +end | |
139 | + | |
140 | +local function debugger_loop(server) | |
141 | + local command | |
142 | + local eval_env = {} | |
143 | + | |
144 | + while true do | |
145 | + local line, status = server:receive() | |
146 | + command = string.sub(line, string.find(line, "^[A-Z]+")) | |
147 | + if command == "SETB" then | |
148 | + local _, _, _, filename, line = string.find(line, "^([A-Z]+)%s+([%w%p]+)%s+(%d+)$") | |
149 | + if filename and line then | |
150 | + set_breakpoint(filename, tonumber(line)) | |
151 | + server:send("200 OK\n") | |
152 | + else | |
153 | + server:send("400 Bad Request\n") | |
154 | + end | |
155 | + elseif command == "DELB" then | |
156 | + local _, _, _, filename, line = string.find(line, "^([A-Z]+)%s+([%w%p]+)%s+(%d+)$") | |
157 | + if filename and line then | |
158 | + remove_breakpoint(filename, tonumber(line)) | |
159 | + server:send("200 OK\n") | |
160 | + else | |
161 | + server:send("400 Bad Request\n") | |
162 | + end | |
163 | + elseif command == "EXEC" then | |
164 | + local _, _, chunk = string.find(line, "^[A-Z]+%s+(.+)$") | |
165 | + if chunk then | |
166 | + local func = loadstring(chunk) | |
167 | + local status, res | |
168 | + if func then | |
169 | + setfenv(func, eval_env) | |
170 | + status, res = xpcall(func, debug.traceback) | |
171 | + end | |
172 | + res = tostring(res) | |
173 | + if status then | |
174 | + server:send("200 OK " .. string.len(res) .. "\n") | |
175 | + server:send(res) | |
176 | + else | |
177 | + server:send("401 Error in Expression " .. string.len(res) .. "\n") | |
178 | + server:send(res) | |
179 | + end | |
180 | + else | |
181 | + server:send("400 Bad Request\n") | |
182 | + end | |
183 | + elseif command == "SETW" then | |
184 | + local _, _, exp = string.find(line, "^[A-Z]+%s+(.+)$") | |
185 | + if exp then | |
186 | + local func = loadstring("return(" .. exp .. ")") | |
187 | + local newidx = table.getn(watches) + 1 | |
188 | + watches[newidx] = func | |
189 | + table.setn(watches, newidx) | |
190 | + server:send("200 OK " .. newidx .. "\n") | |
191 | + else | |
192 | + server:send("400 Bad Request\n") | |
193 | + end | |
194 | + elseif command == "DELW" then | |
195 | + local _, _, index = string.find(line, "^[A-Z]+%s+(%d+)$") | |
196 | + index = tonumber(index) | |
197 | + if index then | |
198 | + watches[index] = nil | |
199 | + server:send("200 OK\n") | |
200 | + else | |
201 | + server:send("400 Bad Request\n") | |
202 | + end | |
203 | + elseif command == "RUN" then | |
204 | + server:send("200 OK\n") | |
205 | + local ev, vars, file, line, idx_watch = coroutine.yield() | |
206 | + eval_env = vars | |
207 | + if ev == events.BREAK then | |
208 | + server:send("202 Paused " .. file .. " " .. line .. "\n") | |
209 | + elseif ev == events.WATCH then | |
210 | + server:send("203 Paused " .. file .. " " .. line .. " " .. idx_watch .. "\n") | |
211 | + else | |
212 | + server:send("401 Error in Execution " .. string.len(file) .. "\n") | |
213 | + server:send(file) | |
214 | + end | |
215 | + elseif command == "STEP" then | |
216 | + server:send("200 OK\n") | |
217 | + step_into = true | |
218 | + local ev, vars, file, line, idx_watch = coroutine.yield() | |
219 | + eval_env = vars | |
220 | + if ev == events.BREAK then | |
221 | + server:send("202 Paused " .. file .. " " .. line .. "\n") | |
222 | + elseif ev == events.WATCH then | |
223 | + server:send("203 Paused " .. file .. " " .. line .. " " .. idx_watch .. "\n") | |
224 | + else | |
225 | + server:send("401 Error in Execution " .. string.len(file) .. "\n") | |
226 | + server:send(file) | |
227 | + end | |
228 | + elseif command == "OVER" then | |
229 | + server:send("200 OK\n") | |
230 | + step_over = true | |
231 | + step_level = stack_level | |
232 | + local ev, vars, file, line, idx_watch = coroutine.yield() | |
233 | + eval_env = vars | |
234 | + if ev == events.BREAK then | |
235 | + server:send("202 Paused " .. file .. " " .. line .. "\n") | |
236 | + elseif ev == events.WATCH then | |
237 | + server:send("203 Paused " .. file .. " " .. line .. " " .. idx_watch .. "\n") | |
238 | + else | |
239 | + server:send("401 Error in Execution " .. string.len(file) .. "\n") | |
240 | + server:send(file) | |
241 | + end | |
242 | + else | |
243 | + server:send("400 Bad Request\n") | |
244 | + end | |
245 | + end | |
246 | +end | |
247 | + | |
248 | +coro_debugger = coroutine.create(debugger_loop) | |
249 | + | |
250 | +-- | |
251 | +-- remdebug.engine.config(tab) | |
252 | +-- Configures the engine | |
253 | +-- | |
254 | +function config(tab) | |
255 | + if tab.host then | |
256 | + controller_host = tab.host | |
257 | + end | |
258 | + if tab.port then | |
259 | + controller_port = tab.port | |
260 | + end | |
261 | +end | |
262 | + | |
263 | +-- | |
264 | +-- remdebug.engine.start() | |
265 | +-- Tries to start the debug session by connecting with a controller | |
266 | +-- | |
267 | +function start() | |
268 | + pcall(require, "remdebug.config") | |
269 | + local server = socket.tcp() | |
270 | + server:connect(controller_host, controller_port) | |
271 | + if server then | |
272 | + _TRACEBACK = function (message) | |
273 | + local err = debug.traceback(message) | |
274 | + server:send("401 Error in Execution " .. string.len(err) .. "\n") | |
275 | + server:send(err) | |
276 | + server:close() | |
277 | + return err | |
278 | + end | |
279 | + debug.sethook(debug_hook, "lcr") | |
280 | + return coroutine.resume(coro_debugger, server) | |
281 | + end | |
282 | +end | |
283 | + | ... | ... |
game/thirdparty/socket.lua
0 → 100644
1 | +----------------------------------------------------------------------------- | |
2 | +-- LuaSocket helper module | |
3 | +-- Author: Diego Nehab | |
4 | +-- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $ | |
5 | +----------------------------------------------------------------------------- | |
6 | + | |
7 | +----------------------------------------------------------------------------- | |
8 | +-- Declare module and import dependencies | |
9 | +----------------------------------------------------------------------------- | |
10 | +local base = _G | |
11 | +local string = require("string") | |
12 | +local math = require("math") | |
13 | +local socket = require("socket.core") | |
14 | +module("socket") | |
15 | + | |
16 | +----------------------------------------------------------------------------- | |
17 | +-- Exported auxiliar functions | |
18 | +----------------------------------------------------------------------------- | |
19 | +function connect(address, port, laddress, lport) | |
20 | + local sock, err = socket.tcp() | |
21 | + if not sock then return nil, err end | |
22 | + if laddress then | |
23 | + local res, err = sock:bind(laddress, lport, -1) | |
24 | + if not res then return nil, err end | |
25 | + end | |
26 | + local res, err = sock:connect(address, port) | |
27 | + if not res then return nil, err end | |
28 | + return sock | |
29 | +end | |
30 | + | |
31 | +function bind(host, port, backlog) | |
32 | + local sock, err = socket.tcp() | |
33 | + if not sock then return nil, err end | |
34 | + sock:setoption("reuseaddr", true) | |
35 | + local res, err = sock:bind(host, port) | |
36 | + if not res then return nil, err end | |
37 | + res, err = sock:listen(backlog) | |
38 | + if not res then return nil, err end | |
39 | + return sock | |
40 | +end | |
41 | + | |
42 | +try = newtry() | |
43 | + | |
44 | +function choose(table) | |
45 | + return function(name, opt1, opt2) | |
46 | + if base.type(name) ~= "string" then | |
47 | + name, opt1, opt2 = "default", name, opt1 | |
48 | + end | |
49 | + local f = table[name or "nil"] | |
50 | + if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) | |
51 | + else return f(opt1, opt2) end | |
52 | + end | |
53 | +end | |
54 | + | |
55 | +----------------------------------------------------------------------------- | |
56 | +-- Socket sources and sinks, conforming to LTN12 | |
57 | +----------------------------------------------------------------------------- | |
58 | +-- create namespaces inside LuaSocket namespace | |
59 | +sourcet = {} | |
60 | +sinkt = {} | |
61 | + | |
62 | +BLOCKSIZE = 2048 | |
63 | + | |
64 | +sinkt["close-when-done"] = function(sock) | |
65 | + return base.setmetatable({ | |
66 | + getfd = function() return sock:getfd() end, | |
67 | + dirty = function() return sock:dirty() end | |
68 | + }, { | |
69 | + __call = function(self, chunk, err) | |
70 | + if not chunk then | |
71 | + sock:close() | |
72 | + return 1 | |
73 | + else return sock:send(chunk) end | |
74 | + end | |
75 | + }) | |
76 | +end | |
77 | + | |
78 | +sinkt["keep-open"] = function(sock) | |
79 | + return base.setmetatable({ | |
80 | + getfd = function() return sock:getfd() end, | |
81 | + dirty = function() return sock:dirty() end | |
82 | + }, { | |
83 | + __call = function(self, chunk, err) | |
84 | + if chunk then return sock:send(chunk) | |
85 | + else return 1 end | |
86 | + end | |
87 | + }) | |
88 | +end | |
89 | + | |
90 | +sinkt["default"] = sinkt["keep-open"] | |
91 | + | |
92 | +sink = choose(sinkt) | |
93 | + | |
94 | +sourcet["by-length"] = function(sock, length) | |
95 | + return base.setmetatable({ | |
96 | + getfd = function() return sock:getfd() end, | |
97 | + dirty = function() return sock:dirty() end | |
98 | + }, { | |
99 | + __call = function() | |
100 | + if length <= 0 then return nil end | |
101 | + local size = math.min(socket.BLOCKSIZE, length) | |
102 | + local chunk, err = sock:receive(size) | |
103 | + if err then return nil, err end | |
104 | + length = length - string.len(chunk) | |
105 | + return chunk | |
106 | + end | |
107 | + }) | |
108 | +end | |
109 | + | |
110 | +sourcet["until-closed"] = function(sock) | |
111 | + local done | |
112 | + return base.setmetatable({ | |
113 | + getfd = function() return sock:getfd() end, | |
114 | + dirty = function() return sock:dirty() end | |
115 | + }, { | |
116 | + __call = function() | |
117 | + if done then return nil end | |
118 | + local chunk, err, partial = sock:receive(socket.BLOCKSIZE) | |
119 | + if not err then return chunk | |
120 | + elseif err == "closed" then | |
121 | + sock:close() | |
122 | + done = 1 | |
123 | + return partial | |
124 | + else return nil, err end | |
125 | + end | |
126 | + }) | |
127 | +end | |
128 | + | |
129 | + | |
130 | +sourcet["default"] = sourcet["until-closed"] | |
131 | + | |
132 | +source = choose(sourcet) | |
133 | + | ... | ... |
game/thirdparty/socket/ftp.lua
0 → 100644
1 | +----------------------------------------------------------------------------- | |
2 | +-- FTP support for the Lua language | |
3 | +-- LuaSocket toolkit. | |
4 | +-- Author: Diego Nehab | |
5 | +-- RCS ID: $Id: ftp.lua,v 1.45 2007/07/11 19:25:47 diego Exp $ | |
6 | +----------------------------------------------------------------------------- | |
7 | + | |
8 | +----------------------------------------------------------------------------- | |
9 | +-- Declare module and import dependencies | |
10 | +----------------------------------------------------------------------------- | |
11 | +local base = _G | |
12 | +local table = require("table") | |
13 | +local string = require("string") | |
14 | +local math = require("math") | |
15 | +local socket = require("socket") | |
16 | +local url = require("socket.url") | |
17 | +local tp = require("socket.tp") | |
18 | +local ltn12 = require("ltn12") | |
19 | +module("socket.ftp") | |
20 | + | |
21 | +----------------------------------------------------------------------------- | |
22 | +-- Program constants | |
23 | +----------------------------------------------------------------------------- | |
24 | +-- timeout in seconds before the program gives up on a connection | |
25 | +TIMEOUT = 60 | |
26 | +-- default port for ftp service | |
27 | +PORT = 21 | |
28 | +-- this is the default anonymous password. used when no password is | |
29 | +-- provided in url. should be changed to your e-mail. | |
30 | +USER = "ftp" | |
31 | +PASSWORD = "anonymous@anonymous.org" | |
32 | + | |
33 | +----------------------------------------------------------------------------- | |
34 | +-- Low level FTP API | |
35 | +----------------------------------------------------------------------------- | |
36 | +local metat = { __index = {} } | |
37 | + | |
38 | +function open(server, port, create) | |
39 | + local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create)) | |
40 | + local f = base.setmetatable({ tp = tp }, metat) | |
41 | + -- make sure everything gets closed in an exception | |
42 | + f.try = socket.newtry(function() f:close() end) | |
43 | + return f | |
44 | +end | |
45 | + | |
46 | +function metat.__index:portconnect() | |
47 | + self.try(self.server:settimeout(TIMEOUT)) | |
48 | + self.data = self.try(self.server:accept()) | |
49 | + self.try(self.data:settimeout(TIMEOUT)) | |
50 | +end | |
51 | + | |
52 | +function metat.__index:pasvconnect() | |
53 | + self.data = self.try(socket.tcp()) | |
54 | + self.try(self.data:settimeout(TIMEOUT)) | |
55 | + self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) | |
56 | +end | |
57 | + | |
58 | +function metat.__index:login(user, password) | |
59 | + self.try(self.tp:command("user", user or USER)) | |
60 | + local code, reply = self.try(self.tp:check{"2..", 331}) | |
61 | + if code == 331 then | |
62 | + self.try(self.tp:command("pass", password or PASSWORD)) | |
63 | + self.try(self.tp:check("2..")) | |
64 | + end | |
65 | + return 1 | |
66 | +end | |
67 | + | |
68 | +function metat.__index:pasv() | |
69 | + self.try(self.tp:command("pasv")) | |
70 | + local code, reply = self.try(self.tp:check("2..")) | |
71 | + local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" | |
72 | + local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) | |
73 | + self.try(a and b and c and d and p1 and p2, reply) | |
74 | + self.pasvt = { | |
75 | + ip = string.format("%d.%d.%d.%d", a, b, c, d), | |
76 | + port = p1*256 + p2 | |
77 | + } | |
78 | + if self.server then | |
79 | + self.server:close() | |
80 | + self.server = nil | |
81 | + end | |
82 | + return self.pasvt.ip, self.pasvt.port | |
83 | +end | |
84 | + | |
85 | +function metat.__index:port(ip, port) | |
86 | + self.pasvt = nil | |
87 | + if not ip then | |
88 | + ip, port = self.try(self.tp:getcontrol():getsockname()) | |
89 | + self.server = self.try(socket.bind(ip, 0)) | |
90 | + ip, port = self.try(self.server:getsockname()) | |
91 | + self.try(self.server:settimeout(TIMEOUT)) | |
92 | + end | |
93 | + local pl = math.mod(port, 256) | |
94 | + local ph = (port - pl)/256 | |
95 | + local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") | |
96 | + self.try(self.tp:command("port", arg)) | |
97 | + self.try(self.tp:check("2..")) | |
98 | + return 1 | |
99 | +end | |
100 | + | |
101 | +function metat.__index:send(sendt) | |
102 | + self.try(self.pasvt or self.server, "need port or pasv first") | |
103 | + -- if there is a pasvt table, we already sent a PASV command | |
104 | + -- we just get the data connection into self.data | |
105 | + if self.pasvt then self:pasvconnect() end | |
106 | + -- get the transfer argument and command | |
107 | + local argument = sendt.argument or | |
108 | + url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) | |
109 | + if argument == "" then argument = nil end | |
110 | + local command = sendt.command or "stor" | |
111 | + -- send the transfer command and check the reply | |
112 | + self.try(self.tp:command(command, argument)) | |
113 | + local code, reply = self.try(self.tp:check{"2..", "1.."}) | |
114 | + -- if there is not a a pasvt table, then there is a server | |
115 | + -- and we already sent a PORT command | |
116 | + if not self.pasvt then self:portconnect() end | |
117 | + -- get the sink, source and step for the transfer | |
118 | + local step = sendt.step or ltn12.pump.step | |
119 | + local readt = {self.tp.c} | |
120 | + local checkstep = function(src, snk) | |
121 | + -- check status in control connection while downloading | |
122 | + local readyt = socket.select(readt, nil, 0) | |
123 | + if readyt[tp] then code = self.try(self.tp:check("2..")) end | |
124 | + return step(src, snk) | |
125 | + end | |
126 | + local sink = socket.sink("close-when-done", self.data) | |
127 | + -- transfer all data and check error | |
128 | + self.try(ltn12.pump.all(sendt.source, sink, checkstep)) | |
129 | + if string.find(code, "1..") then self.try(self.tp:check("2..")) end | |
130 | + -- done with data connection | |
131 | + self.data:close() | |
132 | + -- find out how many bytes were sent | |
133 | + local sent = socket.skip(1, self.data:getstats()) | |
134 | + self.data = nil | |
135 | + return sent | |
136 | +end | |
137 | + | |
138 | +function metat.__index:receive(recvt) | |
139 | + self.try(self.pasvt or self.server, "need port or pasv first") | |
140 | + if self.pasvt then self:pasvconnect() end | |
141 | + local argument = recvt.argument or | |
142 | + url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) | |
143 | + if argument == "" then argument = nil end | |
144 | + local command = recvt.command or "retr" | |
145 | + self.try(self.tp:command(command, argument)) | |
146 | + local code = self.try(self.tp:check{"1..", "2.."}) | |
147 | + if not self.pasvt then self:portconnect() end | |
148 | + local source = socket.source("until-closed", self.data) | |
149 | + local step = recvt.step or ltn12.pump.step | |
150 | + self.try(ltn12.pump.all(source, recvt.sink, step)) | |
151 | + if string.find(code, "1..") then self.try(self.tp:check("2..")) end | |
152 | + self.data:close() | |
153 | + self.data = nil | |
154 | + return 1 | |
155 | +end | |
156 | + | |
157 | +function metat.__index:cwd(dir) | |
158 | + self.try(self.tp:command("cwd", dir)) | |
159 | + self.try(self.tp:check(250)) | |
160 | + return 1 | |
161 | +end | |
162 | + | |
163 | +function metat.__index:type(type) | |
164 | + self.try(self.tp:command("type", type)) | |
165 | + self.try(self.tp:check(200)) | |
166 | + return 1 | |
167 | +end | |
168 | + | |
169 | +function metat.__index:greet() | |
170 | + local code = self.try(self.tp:check{"1..", "2.."}) | |
171 | + if string.find(code, "1..") then self.try(self.tp:check("2..")) end | |
172 | + return 1 | |
173 | +end | |
174 | + | |
175 | +function metat.__index:quit() | |
176 | + self.try(self.tp:command("quit")) | |
177 | + self.try(self.tp:check("2..")) | |
178 | + return 1 | |
179 | +end | |
180 | + | |
181 | +function metat.__index:close() | |
182 | + if self.data then self.data:close() end | |
183 | + if self.server then self.server:close() end | |
184 | + return self.tp:close() | |
185 | +end | |
186 | + | |
187 | +----------------------------------------------------------------------------- | |
188 | +-- High level FTP API | |
189 | +----------------------------------------------------------------------------- | |
190 | +local function override(t) | |
191 | + if t.url then | |
192 | + local u = url.parse(t.url) | |
193 | + for i,v in base.pairs(t) do | |
194 | + u[i] = v | |
195 | + end | |
196 | + return u | |
197 | + else return t end | |
198 | +end | |
199 | + | |
200 | +local function tput(putt) | |
201 | + putt = override(putt) | |
202 | + socket.try(putt.host, "missing hostname") | |
203 | + local f = open(putt.host, putt.port, putt.create) | |
204 | + f:greet() | |
205 | + f:login(putt.user, putt.password) | |
206 | + if putt.type then f:type(putt.type) end | |
207 | + f:pasv() | |
208 | + local sent = f:send(putt) | |
209 | + f:quit() | |
210 | + f:close() | |
211 | + return sent | |
212 | +end | |
213 | + | |
214 | +local default = { | |
215 | + path = "/", | |
216 | + scheme = "ftp" | |
217 | +} | |
218 | + | |
219 | +local function parse(u) | |
220 | + local t = socket.try(url.parse(u, default)) | |
221 | + socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") | |
222 | + socket.try(t.host, "missing hostname") | |
223 | + local pat = "^type=(.)$" | |
224 | + if t.params then | |
225 | + t.type = socket.skip(2, string.find(t.params, pat)) | |
226 | + socket.try(t.type == "a" or t.type == "i", | |
227 | + "invalid type '" .. t.type .. "'") | |
228 | + end | |
229 | + return t | |
230 | +end | |
231 | + | |
232 | +local function sput(u, body) | |
233 | + local putt = parse(u) | |
234 | + putt.source = ltn12.source.string(body) | |
235 | + return tput(putt) | |
236 | +end | |
237 | + | |
238 | +put = socket.protect(function(putt, body) | |
239 | + if base.type(putt) == "string" then return sput(putt, body) | |
240 | + else return tput(putt) end | |
241 | +end) | |
242 | + | |
243 | +local function tget(gett) | |
244 | + gett = override(gett) | |
245 | + socket.try(gett.host, "missing hostname") | |
246 | + local f = open(gett.host, gett.port, gett.create) | |
247 | + f:greet() | |
248 | + f:login(gett.user, gett.password) | |
249 | + if gett.type then f:type(gett.type) end | |
250 | + f:pasv() | |
251 | + f:receive(gett) | |
252 | + f:quit() | |
253 | + return f:close() | |
254 | +end | |
255 | + | |
256 | +local function sget(u) | |
257 | + local gett = parse(u) | |
258 | + local t = {} | |
259 | + gett.sink = ltn12.sink.table(t) | |
260 | + tget(gett) | |
261 | + return table.concat(t) | |
262 | +end | |
263 | + | |
264 | +command = socket.protect(function(cmdt) | |
265 | + cmdt = override(cmdt) | |
266 | + socket.try(cmdt.host, "missing hostname") | |
267 | + socket.try(cmdt.command, "missing command") | |
268 | + local f = open(cmdt.host, cmdt.port, cmdt.create) | |
269 | + f:greet() | |
270 | + f:login(cmdt.user, cmdt.password) | |
271 | + f.try(f.tp:command(cmdt.command, cmdt.argument)) | |
272 | + if cmdt.check then f.try(f.tp:check(cmdt.check)) end | |
273 | + f:quit() | |
274 | + return f:close() | |
275 | +end) | |
276 | + | |
277 | +get = socket.protect(function(gett) | |
278 | + if base.type(gett) == "string" then return sget(gett) | |
279 | + else return tget(gett) end | |
280 | +end) | |
281 | + | ... | ... |
game/thirdparty/socket/http.lua
0 → 100644
1 | +----------------------------------------------------------------------------- | |
2 | +-- HTTP/1.1 client support for the Lua language. | |
3 | +-- LuaSocket toolkit. | |
4 | +-- Author: Diego Nehab | |
5 | +-- RCS ID: $Id: http.lua,v 1.71 2007/10/13 23:55:20 diego Exp $ | |
6 | +----------------------------------------------------------------------------- | |
7 | + | |
8 | +----------------------------------------------------------------------------- | |
9 | +-- Declare module and import dependencies | |
10 | +------------------------------------------------------------------------------- | |
11 | +local socket = require("socket") | |
12 | +local url = require("socket.url") | |
13 | +local ltn12 = require("ltn12") | |
14 | +local mime = require("mime") | |
15 | +local string = require("string") | |
16 | +local base = _G | |
17 | +local table = require("table") | |
18 | +module("socket.http") | |
19 | + | |
20 | +----------------------------------------------------------------------------- | |
21 | +-- Program constants | |
22 | +----------------------------------------------------------------------------- | |
23 | +-- connection timeout in seconds | |
24 | +TIMEOUT = 60 | |
25 | +-- default port for document retrieval | |
26 | +PORT = 80 | |
27 | +-- user agent field sent in request | |
28 | +USERAGENT = socket._VERSION | |
29 | + | |
30 | +----------------------------------------------------------------------------- | |
31 | +-- Reads MIME headers from a connection, unfolding where needed | |
32 | +----------------------------------------------------------------------------- | |
33 | +local function receiveheaders(sock, headers) | |
34 | + local line, name, value, err | |
35 | + headers = headers or {} | |
36 | + -- get first line | |
37 | + line, err = sock:receive() | |
38 | + if err then return nil, err end | |
39 | + -- headers go until a blank line is found | |
40 | + while line ~= "" do | |
41 | + -- get field-name and value | |
42 | + name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) | |
43 | + if not (name and value) then return nil, "malformed reponse headers" end | |
44 | + name = string.lower(name) | |
45 | + -- get next line (value might be folded) | |
46 | + line, err = sock:receive() | |
47 | + if err then return nil, err end | |
48 | + -- unfold any folded values | |
49 | + while string.find(line, "^%s") do | |
50 | + value = value .. line | |
51 | + line = sock:receive() | |
52 | + if err then return nil, err end | |
53 | + end | |
54 | + -- save pair in table | |
55 | + if headers[name] then headers[name] = headers[name] .. ", " .. value | |
56 | + else headers[name] = value end | |
57 | + end | |
58 | + return headers | |
59 | +end | |
60 | + | |
61 | +----------------------------------------------------------------------------- | |
62 | +-- Extra sources and sinks | |
63 | +----------------------------------------------------------------------------- | |
64 | +socket.sourcet["http-chunked"] = function(sock, headers) | |
65 | + return base.setmetatable({ | |
66 | + getfd = function() return sock:getfd() end, | |
67 | + dirty = function() return sock:dirty() end | |
68 | + }, { | |
69 | + __call = function() | |
70 | + -- get chunk size, skip extention | |
71 | + local line, err = sock:receive() | |
72 | + if err then return nil, err end | |
73 | + local size = base.tonumber(string.gsub(line, ";.*", ""), 16) | |
74 | + if not size then return nil, "invalid chunk size" end | |
75 | + -- was it the last chunk? | |
76 | + if size > 0 then | |
77 | + -- if not, get chunk and skip terminating CRLF | |
78 | + local chunk, err, part = sock:receive(size) | |
79 | + if chunk then sock:receive() end | |
80 | + return chunk, err | |
81 | + else | |
82 | + -- if it was, read trailers into headers table | |
83 | + headers, err = receiveheaders(sock, headers) | |
84 | + if not headers then return nil, err end | |
85 | + end | |
86 | + end | |
87 | + }) | |
88 | +end | |
89 | + | |
90 | +socket.sinkt["http-chunked"] = function(sock) | |
91 | + return base.setmetatable({ | |
92 | + getfd = function() return sock:getfd() end, | |
93 | + dirty = function() return sock:dirty() end | |
94 | + }, { | |
95 | + __call = function(self, chunk, err) | |
96 | + if not chunk then return sock:send("0\r\n\r\n") end | |
97 | + local size = string.format("%X\r\n", string.len(chunk)) | |
98 | + return sock:send(size .. chunk .. "\r\n") | |
99 | + end | |
100 | + }) | |
101 | +end | |
102 | + | |
103 | +----------------------------------------------------------------------------- | |
104 | +-- Low level HTTP API | |
105 | +----------------------------------------------------------------------------- | |
106 | +local metat = { __index = {} } | |
107 | + | |
108 | +function open(host, port, create) | |
109 | + -- create socket with user connect function, or with default | |
110 | + local c = socket.try((create or socket.tcp)()) | |
111 | + local h = base.setmetatable({ c = c }, metat) | |
112 | + -- create finalized try | |
113 | + h.try = socket.newtry(function() h:close() end) | |
114 | + -- set timeout before connecting | |
115 | + h.try(c:settimeout(TIMEOUT)) | |
116 | + h.try(c:connect(host, port or PORT)) | |
117 | + -- here everything worked | |
118 | + return h | |
119 | +end | |
120 | + | |
121 | +function metat.__index:sendrequestline(method, uri) | |
122 | + local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) | |
123 | + return self.try(self.c:send(reqline)) | |
124 | +end | |
125 | + | |
126 | +function metat.__index:sendheaders(headers) | |
127 | + local h = "\r\n" | |
128 | + for i, v in base.pairs(headers) do | |
129 | + h = i .. ": " .. v .. "\r\n" .. h | |
130 | + end | |
131 | + self.try(self.c:send(h)) | |
132 | + return 1 | |
133 | +end | |
134 | + | |
135 | +function metat.__index:sendbody(headers, source, step) | |
136 | + source = source or ltn12.source.empty() | |
137 | + step = step or ltn12.pump.step | |
138 | + -- if we don't know the size in advance, send chunked and hope for the best | |
139 | + local mode = "http-chunked" | |
140 | + if headers["content-length"] then mode = "keep-open" end | |
141 | + return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) | |
142 | +end | |
143 | + | |
144 | +function metat.__index:receivestatusline() | |
145 | + local status = self.try(self.c:receive(5)) | |
146 | + -- identify HTTP/0.9 responses, which do not contain a status line | |
147 | + -- this is just a heuristic, but is what the RFC recommends | |
148 | + if status ~= "HTTP/" then return nil, status end | |
149 | + -- otherwise proceed reading a status line | |
150 | + status = self.try(self.c:receive("*l", status)) | |
151 | + local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) | |
152 | + return self.try(base.tonumber(code), status) | |
153 | +end | |
154 | + | |
155 | +function metat.__index:receiveheaders() | |
156 | + return self.try(receiveheaders(self.c)) | |
157 | +end | |
158 | + | |
159 | +function metat.__index:receivebody(headers, sink, step) | |
160 | + sink = sink or ltn12.sink.null() | |
161 | + step = step or ltn12.pump.step | |
162 | + local length = base.tonumber(headers["content-length"]) | |
163 | + local t = headers["transfer-encoding"] -- shortcut | |
164 | + local mode = "default" -- connection close | |
165 | + if t and t ~= "identity" then mode = "http-chunked" | |
166 | + elseif base.tonumber(headers["content-length"]) then mode = "by-length" end | |
167 | + return self.try(ltn12.pump.all(socket.source(mode, self.c, length), | |
168 | + sink, step)) | |
169 | +end | |
170 | + | |
171 | +function metat.__index:receive09body(status, sink, step) | |
172 | + local source = ltn12.source.rewind(socket.source("until-closed", self.c)) | |
173 | + source(status) | |
174 | + return self.try(ltn12.pump.all(source, sink, step)) | |
175 | +end | |
176 | + | |
177 | +function metat.__index:close() | |
178 | + return self.c:close() | |
179 | +end | |
180 | + | |
181 | +----------------------------------------------------------------------------- | |
182 | +-- High level HTTP API | |
183 | +----------------------------------------------------------------------------- | |
184 | +local function adjusturi(reqt) | |
185 | + local u = reqt | |
186 | + -- if there is a proxy, we need the full url. otherwise, just a part. | |
187 | + if not reqt.proxy and not PROXY then | |
188 | + u = { | |
189 | + path = socket.try(reqt.path, "invalid path 'nil'"), | |
190 | + params = reqt.params, | |
191 | + query = reqt.query, | |
192 | + fragment = reqt.fragment | |
193 | + } | |
194 | + end | |
195 | + return url.build(u) | |
196 | +end | |
197 | + | |
198 | +local function adjustproxy(reqt) | |
199 | + local proxy = reqt.proxy or PROXY | |
200 | + if proxy then | |
201 | + proxy = url.parse(proxy) | |
202 | + return proxy.host, proxy.port or 3128 | |
203 | + else | |
204 | + return reqt.host, reqt.port | |
205 | + end | |
206 | +end | |
207 | + | |
208 | +local function adjustheaders(reqt) | |
209 | + -- default headers | |
210 | + local lower = { | |
211 | + ["user-agent"] = USERAGENT, | |
212 | + ["host"] = reqt.host, | |
213 | + ["connection"] = "close, TE", | |
214 | + ["te"] = "trailers" | |
215 | + } | |
216 | + -- if we have authentication information, pass it along | |
217 | + if reqt.user and reqt.password then | |
218 | + lower["authorization"] = | |
219 |