/* * Baltisot * Copyright (C) 1999-2007 Nicolas "Pixel" Noble * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: LuaHttp.cc,v 1.19 2007-07-12 11:32:00 pixel Exp $ */ #include "md5.h" #include "Domain.h" #include "LuaHttp.h" #include "LuaHandle.h" #include "LuaTask.h" #include "Base64.h" class LuaDomain : public Domain { public: LuaDomain(Lua * _L, String r); virtual ~LuaDomain(); virtual void Do(const HttpRequest & req, HttpResponse * res) throw (GeneralException); private: Lua * L; static int max_id; int id; }; class LuaLuaDomain : public LuaObject { public: static void pushstatics(Lua *) throw (GeneralException); LuaLuaDomain(LuaDomain *); protected: virtual void pushmembers(Lua *); LuaDomain * d; }; LuaLuaDomain::LuaLuaDomain(LuaDomain * _d) : d(_d) { } enum LuaDomain_methods_t { LUADOMAIN_ONTOP = 0, LUADOMAIN_GETPATTERN, }; enum LuaDomain_functions_t { LUADOMAIN_NEWDOMAIN = 0, LUADOMAIN_IDOMAIN, LUADOMAIN_NDOMAIN, }; struct lua_functypes_t LuaDomain_methods[] = { { LUADOMAIN_ONTOP, "OnTop", 0, 0, { } }, { LUADOMAIN_GETPATTERN, "GetPattern", 0, 0, { } }, { -1, 0, 0, 0, 0 }, }; struct lua_functypes_t LuaDomain_functions[] = { { LUADOMAIN_NEWDOMAIN, "Domain", 2, 2, { LUA_STRING, LUA_FUNCTION } }, { LUADOMAIN_IDOMAIN, "iDomain", 0, 0, { } }, { LUADOMAIN_NDOMAIN, "nDomain", 2, 2, { LUA_USERDATA, LUA_STRING | LUA_NIL } }, { -1, 0, 0, 0, 0 }, }; class sLua_LuaDomain : public Base { public: DECLARE_METHOD(LuaDomain, LUADOMAIN_ONTOP); DECLARE_METHOD(LuaDomain, LUADOMAIN_GETPATTERN); DECLARE_FUNCTION(LuaDomain, LUADOMAIN_NEWDOMAIN); DECLARE_FUNCTION(LuaDomain, LUADOMAIN_IDOMAIN); DECLARE_FUNCTION(LuaDomain, LUADOMAIN_NDOMAIN); private: static int LuaDomain_proceed(Lua * L, int n, LuaDomain * obj, int caller); static int LuaDomain_proceed_statics(Lua * L, int n, int caller); }; void LuaLuaDomain::pushmembers(Lua * L) { pushme(L, d, "LuaDomain"); PUSH_METHOD(LuaDomain, LUADOMAIN_ONTOP); PUSH_METHOD(LuaDomain, LUADOMAIN_GETPATTERN); } void LuaLuaDomain::pushstatics(Lua * L) throw (GeneralException) { CHECK_METHODS(LuaDomain); CHECK_FUNCTIONS(LuaDomain); PUSH_FUNCTION(LuaDomain, LUADOMAIN_NEWDOMAIN); PUSH_FUNCTION(LuaDomain, LUADOMAIN_IDOMAIN); PUSH_FUNCTION(LuaDomain, LUADOMAIN_NDOMAIN); } #define DOMAIN_REGISTRY "DOMAINS_KEYS" #define export_enum(L, n) \ L->push(#n); \ L->push((lua_Number) HttpResponse::n); \ L->settable(LUA_GLOBALSINDEX); LuaHttpResponse::LuaHttpResponse(HttpResponse * _r) : r(_r) { } enum HttpResponse_method_t { HTTPRESPONSE_INDEX = 0, HTTPRESPONSE_NEWINDEX, }; enum HttpResponse_functions_t { HTTPRESPONSE_NEWHTTPRESPONSE = 0, HTTPRESPONSE_BASE64_ENCODE, HTTPRESPONSE_BASE64_DECODE, HTTPRESPONSE_MD5, }; struct lua_functypes_t HttpResponse_methods[] = { { HTTPRESPONSE_INDEX, "index", 1, 1, { LUA_STRING } }, { HTTPRESPONSE_NEWINDEX, "newindex", 2, 2, { LUA_STRING, LUA_ANY } }, { -1, 0, 0, 0, 0 } }; struct lua_functypes_t HttpResponse_functions[] = { { HTTPRESPONSE_NEWHTTPRESPONSE, "HttpResponse", 0, 0, { } }, { HTTPRESPONSE_BASE64_ENCODE, "Base64Encode", 1, 1, { LUA_STRING } }, { HTTPRESPONSE_BASE64_DECODE, "Base64Decode", 1, 1, { LUA_STRING } }, { HTTPRESPONSE_MD5, "MD5", 1, 1, { LUA_STRING } }, { -1, 0, 0, 0, 0 } }; class sLua_HttpResponse : public Base { public: DECLARE_METHOD(HttpResponse, HTTPRESPONSE_INDEX); DECLARE_METHOD(HttpResponse, HTTPRESPONSE_NEWINDEX); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_NEWHTTPRESPONSE); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_ENCODE); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_DECODE); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_MD5); private: static int HttpResponse_proceed(Lua * L, int n, HttpResponse * obj, int caller); static int HttpResponse_proceed_statics(Lua * L, int n, int caller); }; void LuaHttpResponse::pushmembers(Lua * L) { pushme(L, r, "HttpResponse"); PUSH_METAMETHOD(HttpResponse, HTTPRESPONSE_INDEX); PUSH_METAMETHOD(HttpResponse, HTTPRESPONSE_NEWINDEX); } void LuaHttpResponse::pushstatics(Lua * L) throw (GeneralException) { CHECK_METHODS(HttpResponse); CHECK_FUNCTIONS(HttpResponse); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_NEWHTTPRESPONSE); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_ENCODE); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_DECODE); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_MD5); export_enum(L, HTTP_200_OK); export_enum(L, HTTP_301_PERM_MOVED); export_enum(L, HTTP_302_FOUND); export_enum(L, HTTP_400_BAD_REQUEST); export_enum(L, HTTP_401_UNAUTHORIZED); export_enum(L, HTTP_403_FORBIDDEN); export_enum(L, HTTP_404_NOT_FOUND); export_enum(L, HTTP_500_INTERNAL_ERROR); export_enum(L, HTTP_503_SERVICE_UNAVAILABLE); L->push(DOMAIN_REGISTRY); L->newtable(); L->settable(LUA_REGISTRYINDEX); LuaLuaDomain::pushstatics(L); } int sLua_HttpResponse::HttpResponse_proceed(Lua * L, int n, HttpResponse * res, int caller) { String i; int r = 0; switch (caller) { case HTTPRESPONSE_INDEX: i = L->tostring(2); if (i == "mime_type") { L->push(res->mime_type); } else if (i == "location") { L->push(res->location); } else if (i == "server_name") { L->push(res->server_name); } else if (i == "return_code") { L->push((lua_Number) res->return_code); } else if (i == "last_modified") { L->push((lua_Number) res->last_modified); } else if (i == "contents") { { LuaBuffer b(&res->contents); b.push(L); } } else if (i == "cache") { L->push(res->cache); } else { L->error("Unknow field in HttpResponse object: " + i); } r = 1; break; case HTTPRESPONSE_NEWINDEX: i = L->tostring(2); if (i == "mime_type") { res->mime_type = L->tostring(3); } else if (i == "location") { res->location = L->tostring(3); } else if (i == "server_name") { res->server_name = L->tostring(3); } else if (i == "return_code") { res->return_code = HttpResponse::return_code_t(L->tonumber(3)); } else if (i == "last_modified") { res->last_modified = L->tonumber(3); } else if (i == "contents") { L->error("Can't alter field buffer in HttpResponse."); } else if (i == "cache") { res->cache = L->toboolean(3); } else { L->error("Unknow field in HttpResponse object: " + i); } break; } return r; } int sLua_HttpResponse::HttpResponse_proceed_statics(Lua * L, int n, int caller) { int r = 0, l, i; String enc, dec; char * enc_t; const char * dec_t; md5_context ctx; unsigned char md5sum[16]; String md5sum_r; static const char hconv[] = "0123456789ABCDEF"; switch (caller) { case HTTPRESPONSE_NEWHTTPRESPONSE: { LuaHttpResponse r(new HttpResponse()); r.pushdestruct(L); } r = 1; break; case HTTPRESPONSE_BASE64_ENCODE: dec = L->tostring(); dec_t = dec.to_charp(); L->push(Base64::encode(dec_t, dec.strlen())); r = 1; break; case HTTPRESPONSE_BASE64_DECODE: enc_t = (char *) Base64::decode(L->tostring(), &l); enc_t[l] = 0; L->push(enc_t); r = 1; break; case HTTPRESPONSE_MD5: dec = L->tostring(); dec_t = dec.to_charp(); md5_starts(&ctx); md5_update(&ctx, (uint8 *) dec_t, dec.strlen()); md5_finish(&ctx, md5sum); for (i = 0; i < 16; i++) { md5sum_r = md5sum_r + hconv[md5sum[i] >> 4]; md5sum_r = md5sum_r + hconv[md5sum[i] % 16]; } L->push(md5sum_r); r = 1; break; } return r; } LuaDomain::LuaDomain(Lua * _L, String r) : Domain(r), L(_L->Father()) { id = max_id++; L->push(DOMAIN_REGISTRY); L->gettable(LUA_REGISTRYINDEX); L->push((lua_Number) id); L->copy(2); L->settable(); L->pop(); } LuaDomain::~LuaDomain() { L->push(DOMAIN_REGISTRY); L->gettable(LUA_REGISTRYINDEX); L->push((lua_Number) id); L->push(); L->settable(); L->pop(); } void LuaDomain::Do(const HttpRequest & req, HttpResponse * res) throw (GeneralException) { int i; Lua * oldL = L; Lua * L = oldL->thread(true); oldL->pop(); L->push(DOMAIN_REGISTRY); L->gettable(LUA_REGISTRYINDEX); L->push((lua_Number) id); L->gettable(); L->remove(); L->newtable(); L->push("vars"); L->newtable(); for (i = 0; i < req.vars->GetNb(); i++) { char * v = (*(req.vars))[i].strdup(), * p; p = strchr(v, '='); *p = 0; p++; L->push(v); L->push(p); L->settable(); free(v); } L->settable(); L->push("headers"); L->newtable(); for (i = 0; i < req.headers->GetNb(); i++) { char * v = (*(req.headers))[i].strdup(), * p; p = strchr(v, '='); *p = 0; p++; L->push(v); L->push(p); L->settable(); free(v); } L->settable(); L->push("uri"); L->push(req.uri); L->settable(); L->push("login"); L->push(req.login); L->settable(); L->push("password"); L->push(req.password); L->settable(); L->push("lip"); L->push((lua_Number) req.lip); L->settable(); L->push("dip"); L->push((lua_Number) req.dip); L->settable(); L->push("lport"); L->push((lua_Number) req.lport); L->settable(); L->push("dport"); L->push((lua_Number) req.dport); L->settable(); LuaHttpResponse r(res); r.push(L); res->builder = new LuaTask(L, 2); } int LuaDomain::max_id = 1; int sLua_LuaDomain::LuaDomain_proceed(Lua * L, int n, LuaDomain * obj, int caller) { int r = 0; switch (caller) { case LUADOMAIN_ONTOP: obj->OnTop(); break; case LUADOMAIN_GETPATTERN: L->push(obj->GetPattern()); r = 1; break; } return r; } int sLua_LuaDomain::LuaDomain_proceed_statics(Lua * L, int n, int caller) { int r = 0; Domain ** p; switch (caller) { case LUADOMAIN_NEWDOMAIN: { LuaLuaDomain lld(new LuaDomain(L, L->tostring(1))); lld.pushdestruct(L); r = 1; } break; case LUADOMAIN_IDOMAIN: L->getglobal("nDomain"); p = (Domain **) L->newuser(sizeof(Domain *)); *p = 0; L->push(); r = 3; printm(M_INFO, "IDOMAIN called.\n"); break; case LUADOMAIN_NDOMAIN: p = (Domain **) L->touserdata(1); printm(M_INFO, "NDOMAIN called.\n"); if (*p) { printm(M_INFO, "Not first time.\n"); *p = (*p)->Next(); } else { printm(M_INFO, "First time. p = %p\n", Domain::First()); *p = Domain::First(); printm(M_INFO, "First has pattern: "); printm(M_BARE, Domain::First()->GetPattern()); } if (*p) { printm(M_INFO, "Still has data.\n"); printm(M_INFO, "Get pattern = "); printm(M_BARE, (*p)->GetPattern()); L->push((*p)->GetPattern()); } else { printm(M_INFO, "No more data.\n"); L->push(); } r = 1; break; } return r; }