mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 20:23:06 +00:00
Compare commits
11 Commits
v1.0.0-alp
...
v1.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b87f159b4 | ||
|
|
41b447d41a | ||
|
|
c512b5f59a | ||
|
|
fc9b32b4bd | ||
|
|
36ed8679b8 | ||
|
|
a9b1993686 | ||
|
|
05b458ddb2 | ||
|
|
8d8add3710 | ||
|
|
65e7da9793 | ||
|
|
7e5d9b7399 | ||
|
|
92b7b7beff |
@@ -1,3 +1,9 @@
|
|||||||
|
v1.0.0-alpha3 (2015-3-30)
|
||||||
|
-----------
|
||||||
|
* Update sproto (bugfix)
|
||||||
|
* Add async dns query
|
||||||
|
* improve httpc
|
||||||
|
|
||||||
v1.0.0-alpha2 (2015-3-16)
|
v1.0.0-alpha2 (2015-3-16)
|
||||||
-----------
|
-----------
|
||||||
* Update examples client to lua 5.3
|
* Update examples client to lua 5.3
|
||||||
|
|||||||
@@ -39,6 +39,13 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
|||||||
#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
|
#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LUA_VERSION_NUM < 503
|
||||||
|
|
||||||
|
// lua_isinteger is lua 5.3 api
|
||||||
|
#define lua_isinteger lua_isnumber
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lnewproto(lua_State *L) {
|
lnewproto(lua_State *L) {
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
@@ -104,6 +111,7 @@ encode(const struct sproto_arg *args) {
|
|||||||
return luaL_error(L, "The table is too deep");
|
return luaL_error(L, "The table is too deep");
|
||||||
if (args->index > 0) {
|
if (args->index > 0) {
|
||||||
if (args->tagname != self->array_tag) {
|
if (args->tagname != self->array_tag) {
|
||||||
|
// a new array
|
||||||
self->array_tag = args->tagname;
|
self->array_tag = args->tagname;
|
||||||
lua_getfield(L, self->tbl_index, args->tagname);
|
lua_getfield(L, self->tbl_index, args->tagname);
|
||||||
if (lua_isnil(L, -1)) {
|
if (lua_isnil(L, -1)) {
|
||||||
@@ -113,6 +121,10 @@ encode(const struct sproto_arg *args) {
|
|||||||
self->array_index = 0;
|
self->array_index = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!lua_istable(L, -1)) {
|
||||||
|
return luaL_error(L, ".*%s(%d) should be a table (Is a %s)",
|
||||||
|
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||||
|
}
|
||||||
if (self->array_index) {
|
if (self->array_index) {
|
||||||
lua_replace(L, self->array_index);
|
lua_replace(L, self->array_index);
|
||||||
} else {
|
} else {
|
||||||
@@ -144,8 +156,14 @@ encode(const struct sproto_arg *args) {
|
|||||||
}
|
}
|
||||||
switch (args->type) {
|
switch (args->type) {
|
||||||
case SPROTO_TINTEGER: {
|
case SPROTO_TINTEGER: {
|
||||||
lua_Integer v = luaL_checkinteger(L, -1);
|
lua_Integer v;
|
||||||
lua_Integer vh;
|
lua_Integer vh;
|
||||||
|
if (!lua_isinteger(L, -1)) {
|
||||||
|
return luaL_error(L, ".%s[%d] is not an integer (Is a %s)",
|
||||||
|
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||||
|
} else {
|
||||||
|
v = lua_tointeger(L, -1);
|
||||||
|
}
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
// notice: in lua 5.2, lua_Integer maybe 52bit
|
// notice: in lua 5.2, lua_Integer maybe 52bit
|
||||||
vh = v >> 31;
|
vh = v >> 31;
|
||||||
@@ -160,13 +178,23 @@ encode(const struct sproto_arg *args) {
|
|||||||
}
|
}
|
||||||
case SPROTO_TBOOLEAN: {
|
case SPROTO_TBOOLEAN: {
|
||||||
int v = lua_toboolean(L, -1);
|
int v = lua_toboolean(L, -1);
|
||||||
|
if (!lua_isboolean(L,-1)) {
|
||||||
|
return luaL_error(L, ".%s[%d] is not a boolean (Is a %s)",
|
||||||
|
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||||
|
}
|
||||||
*(int *)args->value = v;
|
*(int *)args->value = v;
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
case SPROTO_TSTRING: {
|
case SPROTO_TSTRING: {
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
const char * str = luaL_checklstring(L, -1, &sz);
|
const char * str;
|
||||||
|
if (!lua_isstring(L, -1)) {
|
||||||
|
return luaL_error(L, ".%s[%d] is not a string (Is a %s)",
|
||||||
|
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||||
|
} else {
|
||||||
|
str = lua_tolstring(L, -1, &sz);
|
||||||
|
}
|
||||||
if (sz > args->length)
|
if (sz > args->length)
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(args->value, str, sz);
|
memcpy(args->value, str, sz);
|
||||||
@@ -176,16 +204,21 @@ encode(const struct sproto_arg *args) {
|
|||||||
case SPROTO_TSTRUCT: {
|
case SPROTO_TSTRUCT: {
|
||||||
struct encode_ud sub;
|
struct encode_ud sub;
|
||||||
int r;
|
int r;
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
if (!lua_istable(L, top)) {
|
||||||
|
return luaL_error(L, ".%s[%d] is not a table (Is a %s)",
|
||||||
|
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||||
|
}
|
||||||
sub.L = L;
|
sub.L = L;
|
||||||
sub.st = args->subtype;
|
sub.st = args->subtype;
|
||||||
sub.tbl_index = lua_gettop(L);
|
sub.tbl_index = top;
|
||||||
sub.array_tag = NULL;
|
sub.array_tag = NULL;
|
||||||
sub.array_index = 0;
|
sub.array_index = 0;
|
||||||
sub.deep = self->deep + 1;
|
sub.deep = self->deep + 1;
|
||||||
lua_pushnil(L); // prepare an iterator slot
|
lua_pushnil(L); // prepare an iterator slot
|
||||||
sub.iter_index = sub.tbl_index + 1;
|
sub.iter_index = sub.tbl_index + 1;
|
||||||
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
|
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
|
||||||
lua_pop(L,2); // pop the value and the iterator slot
|
lua_settop(L, top-1); // pop the value
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -222,29 +255,30 @@ lencode(lua_State *L) {
|
|||||||
struct encode_ud self;
|
struct encode_ud self;
|
||||||
void * buffer = lua_touserdata(L, lua_upvalueindex(1));
|
void * buffer = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
int sz = lua_tointeger(L, lua_upvalueindex(2));
|
int sz = lua_tointeger(L, lua_upvalueindex(2));
|
||||||
|
int tbl_index = 2;
|
||||||
struct sproto_type * st = lua_touserdata(L, 1);
|
struct sproto_type * st = lua_touserdata(L, 1);
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
return luaL_argerror(L, 1, "Need a sproto_type object");
|
return luaL_argerror(L, 1, "Need a sproto_type object");
|
||||||
}
|
}
|
||||||
luaL_checktype(L, 2, LUA_TTABLE);
|
luaL_checktype(L, tbl_index, LUA_TTABLE);
|
||||||
luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL);
|
luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL);
|
||||||
self.L = L;
|
self.L = L;
|
||||||
self.st = st;
|
self.st = st;
|
||||||
self.tbl_index = 2;
|
self.tbl_index = tbl_index;
|
||||||
|
for (;;) {
|
||||||
|
int r;
|
||||||
self.array_tag = NULL;
|
self.array_tag = NULL;
|
||||||
self.array_index = 0;
|
self.array_index = 0;
|
||||||
self.deep = 0;
|
self.deep = 0;
|
||||||
lua_pushnil(L); // for iterator (stack 3)
|
|
||||||
self.iter_index = 3;
|
lua_settop(L, tbl_index);
|
||||||
for (;;) {
|
lua_pushnil(L); // for iterator (stack slot 3)
|
||||||
int r = sproto_encode(st, buffer, sz, encode, &self);
|
self.iter_index = tbl_index+1;
|
||||||
|
|
||||||
|
r = sproto_encode(st, buffer, sz, encode, &self);
|
||||||
if (r<0) {
|
if (r<0) {
|
||||||
buffer = expand_buffer(L, sz, sz*2);
|
buffer = expand_buffer(L, sz, sz*2);
|
||||||
sz *= 2;
|
sz *= 2;
|
||||||
// reset iterator slot
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_replace(L, 3);
|
|
||||||
} else {
|
} else {
|
||||||
lua_pushlstring(L, buffer, r);
|
lua_pushlstring(L, buffer, r);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
290
lualib/dns.lua
Normal file
290
lualib/dns.lua
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
--[[
|
||||||
|
lua dns resolver library
|
||||||
|
See https://github.com/xjdrew/levent/blob/master/levent/dns.lua for more detail
|
||||||
|
|
||||||
|
-- resource record type:
|
||||||
|
-- TYPE value and meaning
|
||||||
|
-- A 1 a host address
|
||||||
|
-- NS 2 an authoritative name server
|
||||||
|
-- MD 3 a mail destination (Obsolete - use MX)
|
||||||
|
-- MF 4 a mail forwarder (Obsolete - use MX)
|
||||||
|
-- CNAME 5 the canonical name for an alias
|
||||||
|
-- SOA 6 marks the start of a zone of authority
|
||||||
|
-- MB 7 a mailbox domain name (EXPERIMENTAL)
|
||||||
|
-- MG 8 a mail group member (EXPERIMENTAL)
|
||||||
|
-- MR 9 a mail rename domain name (EXPERIMENTAL)
|
||||||
|
-- NULL 10 a null RR (EXPERIMENTAL)
|
||||||
|
-- WKS 11 a well known service description
|
||||||
|
-- PTR 12 a domain name pointer
|
||||||
|
-- HINFO 13 host information
|
||||||
|
-- MINFO 14 mailbox or mail list information
|
||||||
|
-- MX 15 mail exchange
|
||||||
|
-- TXT 16 text strings
|
||||||
|
-- AAAA 28 a ipv6 host address
|
||||||
|
-- only appear in the question section:
|
||||||
|
-- AXFR 252 A request for a transfer of an entire zone
|
||||||
|
-- MAILB 253 A request for mailbox-related records (MB, MG or MR)
|
||||||
|
-- MAILA 254 A request for mail agent RRs (Obsolete - see MX)
|
||||||
|
-- * 255 A request for all records
|
||||||
|
--
|
||||||
|
-- resource recode class:
|
||||||
|
-- IN 1 the Internet
|
||||||
|
-- CS 2 the CSNET class (Obsolete - used only for examples in some obsolete RFCs)
|
||||||
|
-- CH 3 the CHAOS class
|
||||||
|
-- HS 4 Hesiod [Dyer 87]
|
||||||
|
-- only appear in the question section:
|
||||||
|
-- * 255 any class
|
||||||
|
-- ]]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
-- struct header {
|
||||||
|
-- uint16_t tid # identifier assigned by the program that generates any kind of query.
|
||||||
|
-- uint16_t flags # flags
|
||||||
|
-- uint16_t qdcount # the number of entries in the question section.
|
||||||
|
-- uint16_t ancount # the number of resource records in the answer section.
|
||||||
|
-- uint16_t nscount # the number of name server resource records in the authority records section.
|
||||||
|
-- uint16_t arcount # the number of resource records in the additional records section.
|
||||||
|
-- }
|
||||||
|
--
|
||||||
|
-- request body:
|
||||||
|
-- struct request {
|
||||||
|
-- string name
|
||||||
|
-- uint16_t atype
|
||||||
|
-- uint16_t class
|
||||||
|
-- }
|
||||||
|
--
|
||||||
|
-- response body:
|
||||||
|
-- struct response {
|
||||||
|
-- string name
|
||||||
|
-- uint16_t atype
|
||||||
|
-- uint16_t class
|
||||||
|
-- uint16_t ttl
|
||||||
|
-- uint16_t rdlength
|
||||||
|
-- string rdata
|
||||||
|
-- }
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local skynet = require "skynet"
|
||||||
|
local socket = require "socket"
|
||||||
|
|
||||||
|
local MAX_DOMAIN_LEN = 1024
|
||||||
|
local MAX_LABEL_LEN = 63
|
||||||
|
local MAX_PACKET_LEN = 2048
|
||||||
|
local DNS_HEADER_LEN = 12
|
||||||
|
|
||||||
|
local QTYPE = {
|
||||||
|
A = 1,
|
||||||
|
CNAME = 5,
|
||||||
|
AAAA = 28,
|
||||||
|
}
|
||||||
|
|
||||||
|
local QCLASS = {
|
||||||
|
IN = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
local dns = {}
|
||||||
|
|
||||||
|
local function verify_domain_name(name)
|
||||||
|
if #name > MAX_DOMAIN_LEN then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not name:match("^[%l%d-%.]+$") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for w in name:gmatch("([%w-]+)%.?") do
|
||||||
|
if #w > MAX_LABEL_LEN then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local next_tid = 1
|
||||||
|
local function gen_tid()
|
||||||
|
local tid = next_tid
|
||||||
|
next_tid = next_tid + 1
|
||||||
|
return tid
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pack_header(t)
|
||||||
|
return string.pack(">HHHHHH",
|
||||||
|
t.tid, t.flags, t.qdcount, t.ancount or 0, t.nscount or 0, t.arcount or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pack_question(name, qtype, qclass)
|
||||||
|
local labels = {}
|
||||||
|
for w in name:gmatch("([%w-]+)%.?") do
|
||||||
|
table.insert(labels, string.pack("s1",w))
|
||||||
|
end
|
||||||
|
table.insert(labels, '\0')
|
||||||
|
table.insert(labels, string.pack(">HH", qtype, qclass))
|
||||||
|
return table.concat(labels)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpack_header(chunk)
|
||||||
|
local tid, flags, qdcount, ancount, nscount, arcount, left = string.unpack(">HHHHHH", chunk)
|
||||||
|
return {
|
||||||
|
tid = tid,
|
||||||
|
flags = flags,
|
||||||
|
qdcount = qdcount,
|
||||||
|
ancount = ancount,
|
||||||
|
nscount = nscount,
|
||||||
|
arcount = arcount
|
||||||
|
}, left
|
||||||
|
end
|
||||||
|
|
||||||
|
-- unpack a resource name
|
||||||
|
local function unpack_name(chunk, left)
|
||||||
|
local t = {}
|
||||||
|
local jump_pointer
|
||||||
|
local tag, offset, label
|
||||||
|
while true do
|
||||||
|
tag, left = string.unpack("B", chunk, left)
|
||||||
|
if tag & 0xc0 == 0xc0 then
|
||||||
|
-- pointer
|
||||||
|
offset,left = string.unpack(">H", chunk, left - 1)
|
||||||
|
offset = offset & 0x3fff
|
||||||
|
if not jump_pointer then
|
||||||
|
jump_pointer = left
|
||||||
|
end
|
||||||
|
-- offset is base 0, need to plus 1
|
||||||
|
left = offset + 1
|
||||||
|
elseif tag == 0 then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
label, left = string.unpack("s1", chunk, left - 1)
|
||||||
|
t[#t+1] = label
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(t, "."), jump_pointer or left
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpack_question(chunk, left)
|
||||||
|
local name, left = unpack_name(chunk, left)
|
||||||
|
local atype, class, left = string.unpack(">HH", chunk, left)
|
||||||
|
return {
|
||||||
|
name = name,
|
||||||
|
atype = atype,
|
||||||
|
class = class
|
||||||
|
}, left
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpack_answer(chunk, left)
|
||||||
|
local name, left = unpack_name(chunk, left)
|
||||||
|
local atype, class, ttl, rdata, left = string.unpack(">HHI4s2", chunk, left)
|
||||||
|
return {
|
||||||
|
name = name,
|
||||||
|
atype = atype,
|
||||||
|
class = class,
|
||||||
|
ttl = ttl,
|
||||||
|
rdata = rdata
|
||||||
|
},left
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpack_rdata(qtype, chunk)
|
||||||
|
if qtype == QTYPE.A then
|
||||||
|
local a,b,c,d = string.unpack("BBBB", chunk)
|
||||||
|
return string.format("%d.%d.%d.%d", a,b,c,d)
|
||||||
|
elseif qtype == QTYPE.AAAA then
|
||||||
|
local a,b,c,d,e,f,g,h = string.unpack(">HHHHHHHH", chunk)
|
||||||
|
return string.format("%x:%x:%x:%x:%x:%x:%x:%x", a, b, c, d, e, f, g, h)
|
||||||
|
else
|
||||||
|
error("Error qtype " .. qtype)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local dns_server
|
||||||
|
local request_pool = {}
|
||||||
|
|
||||||
|
local function resolve(content)
|
||||||
|
if #content < DNS_HEADER_LEN then
|
||||||
|
-- drop
|
||||||
|
skynet.error("Recv an invalid package when dns query")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local answer_header,left = unpack_header(content)
|
||||||
|
-- verify answer
|
||||||
|
assert(answer_header.qdcount == 1, "malformed packet")
|
||||||
|
|
||||||
|
local resp = request_pool[answer_header.tid]
|
||||||
|
if not resp then
|
||||||
|
skynet.error("Recv an invalid tid when dns query")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local question,left = unpack_question(content, left)
|
||||||
|
if question.name ~= resp.name then
|
||||||
|
skynet.error("Recv an invalid name when dns query")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ttl
|
||||||
|
local answer
|
||||||
|
local answers = {}
|
||||||
|
for i=1, answer_header.ancount do
|
||||||
|
answer, left = unpack_answer(content, left)
|
||||||
|
-- only extract qtype address
|
||||||
|
if answer.atype == resp.qtype then
|
||||||
|
local ip = unpack_rdata(resp.qtype, answer.rdata)
|
||||||
|
ttl = ttl and math.min(ttl, answer.ttl) or answer.ttl
|
||||||
|
answers[#answers+1] = ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #answers > 0 then
|
||||||
|
resp.answers = answers
|
||||||
|
end
|
||||||
|
|
||||||
|
skynet.wakeup(resp.co)
|
||||||
|
end
|
||||||
|
|
||||||
|
function dns.server(server, port)
|
||||||
|
if not server then
|
||||||
|
local f = assert(io.open "/etc/resolv.conf")
|
||||||
|
for line in f:lines() do
|
||||||
|
server = line:match("%s*nameserver%s+([^%s]+)")
|
||||||
|
if server then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(server, "Can't get nameserver")
|
||||||
|
end
|
||||||
|
dns_server = socket.udp(function(data, sz, from)
|
||||||
|
resolve(skynet.tostring(data,sz))
|
||||||
|
end)
|
||||||
|
socket.udp_connect(dns_server, server, port or 53)
|
||||||
|
return server
|
||||||
|
end
|
||||||
|
|
||||||
|
local function suspend(tid, name, qtype)
|
||||||
|
local req = {
|
||||||
|
name = name,
|
||||||
|
tid = tid,
|
||||||
|
qtype = qtype,
|
||||||
|
time = skynet.now(), -- for timeout
|
||||||
|
co = coroutine.running(),
|
||||||
|
}
|
||||||
|
request_pool[tid] = req
|
||||||
|
skynet.wait()
|
||||||
|
local answers = request_pool[tid].answers
|
||||||
|
request_pool[tid] = nil
|
||||||
|
assert(answers, "no ip")
|
||||||
|
return answers[1], answers
|
||||||
|
end
|
||||||
|
|
||||||
|
function dns.resolve(name, ipv6)
|
||||||
|
local qtype = ipv6 and QTYPE.AAAA or QTYPE.A
|
||||||
|
local name = name:lower()
|
||||||
|
assert(verify_domain_name(name) , "illegal name")
|
||||||
|
local question_header = {
|
||||||
|
tid = gen_tid(),
|
||||||
|
flags = 0x100, -- flags: 00000001 00000000, set RD
|
||||||
|
qdcount = 1,
|
||||||
|
}
|
||||||
|
local req = pack_header(question_header) .. pack_question(name, qtype, QCLASS.IN)
|
||||||
|
assert(dns_server, "Call dns.server fist")
|
||||||
|
socket.write(dns_server, req)
|
||||||
|
return suspend(question_header.tid, name, qtype)
|
||||||
|
end
|
||||||
|
|
||||||
|
return dns
|
||||||
@@ -14,10 +14,15 @@ local function request(fd, method, host, url, recvheader, header, content)
|
|||||||
for k,v in pairs(header) do
|
for k,v in pairs(header) do
|
||||||
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
|
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
|
||||||
end
|
end
|
||||||
|
if header.host then
|
||||||
|
host = ""
|
||||||
|
end
|
||||||
|
else
|
||||||
|
host = string.format("host:%s\r\n",host)
|
||||||
end
|
end
|
||||||
|
|
||||||
if content then
|
if content then
|
||||||
local data = string.format("%s %s HTTP/1.1\r\nhost:%s\r\ncontent-length:%d\r\n%s\r\n%s", method, url, host, #content, header_content, content)
|
local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n%s\r\n%s", method, url, host, #content, header_content, content)
|
||||||
write(data)
|
write(data)
|
||||||
else
|
else
|
||||||
local request_header = string.format("%s %s HTTP/1.1\r\nhost:%s\r\ncontent-length:0\r\n%s\r\n", method, url, host, header_content)
|
local request_header = string.format("%s %s HTTP/1.1\r\nhost:%s\r\ncontent-length:0\r\n%s\r\n", method, url, host, header_content)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ local internal = require "http.internal"
|
|||||||
|
|
||||||
local table = table
|
local table = table
|
||||||
local string = string
|
local string = string
|
||||||
|
local type = type
|
||||||
|
|
||||||
local httpd = {}
|
local httpd = {}
|
||||||
|
|
||||||
@@ -113,8 +114,14 @@ local function writeall(writefunc, statuscode, bodyfunc, header)
|
|||||||
writefunc(statusline)
|
writefunc(statusline)
|
||||||
if header then
|
if header then
|
||||||
for k,v in pairs(header) do
|
for k,v in pairs(header) do
|
||||||
|
if type(v) == "table" then
|
||||||
|
for _,v in ipairs(v) do
|
||||||
writefunc(string.format("%s: %s\r\n", k,v))
|
writefunc(string.format("%s: %s\r\n", k,v))
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
writefunc(string.format("%s: %s\r\n", k,v))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local t = type(bodyfunc)
|
local t = type(bodyfunc)
|
||||||
if t == "string" then
|
if t == "string" then
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
local table = table
|
||||||
|
local type = type
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
local LIMIT = 8192
|
local LIMIT = 8192
|
||||||
@@ -83,7 +86,12 @@ function M.parseheader(lines, from, header)
|
|||||||
end
|
end
|
||||||
name = name:lower()
|
name = name:lower()
|
||||||
if header[name] then
|
if header[name] then
|
||||||
header[name] = header[name] .. ", " .. value
|
local v = header[name]
|
||||||
|
if type(v) == "table" then
|
||||||
|
table.insert(v, value)
|
||||||
|
else
|
||||||
|
header[name] = { v , value }
|
||||||
|
end
|
||||||
else
|
else
|
||||||
header[name] = value
|
header[name] = value
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ local typedef = P {
|
|||||||
FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename * mainkey^0)),
|
FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename * mainkey^0)),
|
||||||
STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}",
|
STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}",
|
||||||
TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ),
|
TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ),
|
||||||
SUBPROTO = Ct((C"request" + C"response") * blanks * (name + V"STRUCT")),
|
SUBPROTO = Ct((C"request" + C"response") * blanks * (typename + V"STRUCT")),
|
||||||
PROTOCOL = namedpat("protocol", name * blanks * tag * blank0 * P"{" * multipat(V"SUBPROTO") * P"}"),
|
PROTOCOL = namedpat("protocol", name * blanks * tag * blank0 * P"{" * multipat(V"SUBPROTO") * P"}"),
|
||||||
ALL = multipat(V"TYPE" + V"PROTOCOL"),
|
ALL = multipat(V"TYPE" + V"PROTOCOL"),
|
||||||
}
|
}
|
||||||
@@ -186,6 +186,32 @@ local function checktype(types, ptype, t)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function check_protocol(r)
|
||||||
|
local map = {}
|
||||||
|
local type = r.type
|
||||||
|
for name, v in pairs(r.protocol) do
|
||||||
|
local tag = v.tag
|
||||||
|
local request = v.request
|
||||||
|
local response = v.response
|
||||||
|
local p = map[tag]
|
||||||
|
|
||||||
|
if p then
|
||||||
|
error(string.format("redefined protocol tag %d at %s", tag, name))
|
||||||
|
end
|
||||||
|
|
||||||
|
if request and not type[request] then
|
||||||
|
error(string.format("Undefined request type %s in protocol %s", request, name))
|
||||||
|
end
|
||||||
|
|
||||||
|
if response and not type[response] then
|
||||||
|
error(string.format("Undefined response type %s in protocol %s", response, name))
|
||||||
|
end
|
||||||
|
|
||||||
|
map[tag] = v
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
local function flattypename(r)
|
local function flattypename(r)
|
||||||
for typename, t in pairs(r.type) do
|
for typename, t in pairs(r.type) do
|
||||||
for _, f in pairs(t) do
|
for _, f in pairs(t) do
|
||||||
@@ -204,7 +230,7 @@ end
|
|||||||
local function parser(text,filename)
|
local function parser(text,filename)
|
||||||
local state = { file = filename, pos = 0, line = 1 }
|
local state = { file = filename, pos = 0, line = 1 }
|
||||||
local r = lpeg.match(proto * -1 + exception , text , 1, state )
|
local r = lpeg.match(proto * -1 + exception , text , 1, state )
|
||||||
return flattypename(adjust(r))
|
return flattypename(check_protocol(adjust(r)))
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|||||||
11
test/testdns.lua
Normal file
11
test/testdns.lua
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
local skynet = require "skynet"
|
||||||
|
local dns = require "dns"
|
||||||
|
|
||||||
|
skynet.start(function()
|
||||||
|
print("nameserver:", dns.server()) -- set nameserver
|
||||||
|
-- you can specify the server like dns.server("8.8.4.4", 53)
|
||||||
|
local ip, ips = dns.resolve "github.com"
|
||||||
|
for k,v in ipairs(ips) do
|
||||||
|
print("github.com",v)
|
||||||
|
end
|
||||||
|
end)
|
||||||
@@ -1,16 +1,24 @@
|
|||||||
local skynet = require "skynet"
|
local skynet = require "skynet"
|
||||||
local httpc = require "http.httpc"
|
local httpc = require "http.httpc"
|
||||||
|
local dns = require "dns"
|
||||||
|
|
||||||
skynet.start(function()
|
skynet.start(function()
|
||||||
print("GET baidu.com")
|
print("GET baidu.com")
|
||||||
local header = {}
|
local respheader = {}
|
||||||
local status, body = httpc.get("baidu.com", "/", header)
|
local status, body = httpc.get("baidu.com", "/", respheader)
|
||||||
print("[header] =====>")
|
print("[header] =====>")
|
||||||
for k,v in pairs(header) do
|
for k,v in pairs(respheader) do
|
||||||
print(k,v)
|
print(k,v)
|
||||||
end
|
end
|
||||||
print("[body] =====>", status)
|
print("[body] =====>", status)
|
||||||
print(body)
|
print(body)
|
||||||
|
|
||||||
|
local respheader = {}
|
||||||
|
dns.server()
|
||||||
|
local ip = dns.resolve "baidu.com"
|
||||||
|
print(string.format("GET %s (baidu.com)", ip))
|
||||||
|
local status, body = httpc.get("baidu.com", "/", respheader, { host = "baidu.com" })
|
||||||
|
print(status)
|
||||||
|
|
||||||
skynet.exit()
|
skynet.exit()
|
||||||
end)
|
end)
|
||||||
|
|||||||
Reference in New Issue
Block a user