Fix id<->url decoding
Some urls should have been url-encoded, fix this issue in a way that won't break old urls
This commit is contained in:
parent
45e1ba3fcb
commit
0f17393cd8
188
src/libkore.c
188
src/libkore.c
|
@ -9,6 +9,7 @@
|
||||||
#include <lualib.h>
|
#include <lualib.h>
|
||||||
//#include <inet/in.h>//linux only I guess
|
//#include <inet/in.h>//linux only I guess
|
||||||
#include "libkore.h"
|
#include "libkore.h"
|
||||||
|
#include "smr.h" //Where the error handler code is
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
#define LUA_PUSH_CONST(L,a) lua_pushnumber(L,a); lua_setfield(L,-2,#a);
|
#define LUA_PUSH_CONST(L,a) lua_pushnumber(L,a); lua_setfield(L,-2,#a);
|
||||||
|
@ -25,12 +26,18 @@ luaL_checkrequest(lua_State *L, int pos){
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
http_response(request::userdata, errcode::number, data::string)
|
http_response(request::userdata, errcode::number, (data::string | nil))
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
lhttp_response(lua_State *L){
|
lhttp_response(lua_State *L){
|
||||||
size_t size;
|
size_t size;
|
||||||
const char *data = luaL_checklstring(L,-1,&size);
|
const char *data;
|
||||||
|
if(lua_isnil(L,-1)){
|
||||||
|
data = NULL;
|
||||||
|
size = 0;
|
||||||
|
}else{
|
||||||
|
data = luaL_checklstring(L,-1,&size);
|
||||||
|
}
|
||||||
int httpcode = luaL_checkint(L,-2);
|
int httpcode = luaL_checkint(L,-2);
|
||||||
struct http_request *req = luaL_checkrequest(L,-3);
|
struct http_request *req = luaL_checkrequest(L,-3);
|
||||||
http_response(req,httpcode,data,size);
|
http_response(req,httpcode,data,size);
|
||||||
|
@ -38,6 +45,150 @@ lhttp_response(lua_State *L){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*Helpers for response coroutines*/
|
||||||
|
int
|
||||||
|
coroutine_iter_sent(struct netbuf *buf){
|
||||||
|
printf("Iter sent called\n");
|
||||||
|
struct co_obj *obj = (struct co_obj*)buf->extra;
|
||||||
|
lua_State *L = obj->L;
|
||||||
|
printf("\tbuf:%p\n",(void*)buf);
|
||||||
|
printf("\tobj:%p\n",(void*)obj);
|
||||||
|
printf("\tL:%p\n",(void*)L);
|
||||||
|
|
||||||
|
printf("Top is: %d\n",lua_gettop(L));
|
||||||
|
printf("Getting status...\n");
|
||||||
|
lua_getglobal(L,"coroutine");
|
||||||
|
printf("Found coroutine...\n");
|
||||||
|
lua_getfield(L,-1,"status");
|
||||||
|
printf("Found status...\n");
|
||||||
|
lua_rawgeti(L,LUA_REGISTRYINDEX,obj->ref);
|
||||||
|
printf("About to get status\n");
|
||||||
|
lua_call(L,1,1);
|
||||||
|
printf("Status got\n");
|
||||||
|
const char *status = luaL_checklstring(L,-1,NULL);
|
||||||
|
printf("status in sent: %s\n",status);
|
||||||
|
|
||||||
|
if(strcmp(status,"dead") == 0){
|
||||||
|
printf("Cleanup\n");
|
||||||
|
return KORE_RESULT_OK;
|
||||||
|
}else{
|
||||||
|
printf("About to call iter_next from iter_sent\n");
|
||||||
|
return coroutine_iter_next(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char response[] = "0\r\n\r\n";
|
||||||
|
|
||||||
|
int coroutine_iter_next(struct co_obj *obj){
|
||||||
|
printf("Coroutine iter next called\n");
|
||||||
|
lua_State *L = obj->L;
|
||||||
|
lua_getglobal(L,"coroutine");
|
||||||
|
lua_getfield(L,-1,"status");
|
||||||
|
lua_rawgeti(L,LUA_REGISTRYINDEX,obj->ref);
|
||||||
|
lua_call(L,1,1);
|
||||||
|
const char *status = luaL_checklstring(L,-1,NULL);
|
||||||
|
printf("status in next: %s\n",status);
|
||||||
|
lua_pop(L,lua_gettop(L));
|
||||||
|
printf("Calling resume\n");
|
||||||
|
lua_getglobal(L,"coroutine");
|
||||||
|
printf("Getting resume()\n");
|
||||||
|
lua_getfield(L,-1,"resume");
|
||||||
|
printf("Getting function\n");
|
||||||
|
lua_rawgeti(L,LUA_REGISTRYINDEX,obj->ref);
|
||||||
|
printf("Checking type\n");
|
||||||
|
luaL_checktype(L,-1,LUA_TTHREAD);
|
||||||
|
printf("About to call resume()\n");
|
||||||
|
int err = lua_pcall(L,1,2,0);
|
||||||
|
printf("Done calling resume()\n");
|
||||||
|
if(!lua_toboolean(L,-2)){ //Runtime error
|
||||||
|
printf("Runtime error\n");
|
||||||
|
lua_pushstring(L,":\n");//"error",":"
|
||||||
|
printf("top1:%d\n",lua_gettop(L));
|
||||||
|
lua_getglobal(L,"debug");//"error",":",{debug}
|
||||||
|
printf("top2:%d\n",lua_gettop(L));
|
||||||
|
lua_getfield(L,-1,"traceback");//"error",":",{debug},debug.traceback()
|
||||||
|
printf("top3:%d\n",lua_gettop(L));
|
||||||
|
lua_call(L,0,1);//"error",":",{debug},"traceback"
|
||||||
|
printf("top4:%d\n",lua_gettop(L));
|
||||||
|
lua_remove(L,-2);//"error",":","traceback"
|
||||||
|
printf("top5:%d\n",lua_gettop(L));
|
||||||
|
lua_concat(L,3);
|
||||||
|
printf("top6:%d\n",lua_gettop(L));
|
||||||
|
size_t size;
|
||||||
|
const char *s = luaL_checklstring(L,-1,&size);
|
||||||
|
printf("Error: %s\n",s);
|
||||||
|
lua_pop(L,lua_gettop(L));
|
||||||
|
return (KORE_RESULT_ERROR);
|
||||||
|
}
|
||||||
|
//No runtime error
|
||||||
|
if(lua_type(L,-1) == LUA_TSTRING){
|
||||||
|
printf("Data yielded\n");
|
||||||
|
size_t size;
|
||||||
|
const char *data = luaL_checklstring(L,-1,&size);
|
||||||
|
struct netbuf *nb;
|
||||||
|
printf("Yielding data stream size %lld\n",size);
|
||||||
|
struct kore_buf *kb = kore_buf_alloc(0);
|
||||||
|
kore_buf_appendf(kb,"%x\r\n",size);
|
||||||
|
kore_buf_append(kb,data,size);
|
||||||
|
size_t ssize;
|
||||||
|
char *sstr = kore_buf_stringify(kb,&ssize);
|
||||||
|
net_send_stream(obj->c, sstr, ssize, coroutine_iter_sent, &nb);
|
||||||
|
nb->extra = obj;
|
||||||
|
lua_pop(L,lua_gettop(L));
|
||||||
|
kore_buf_free(kb);
|
||||||
|
return (KORE_RESULT_RETRY);
|
||||||
|
//return err == 0 ? (KORE_RESULT_OK) : (KORE_RESULT_RETRY);
|
||||||
|
}else if(lua_type(L,-1) == LUA_TNIL){
|
||||||
|
printf("Done with function\n");
|
||||||
|
struct netbuf *nb;
|
||||||
|
printf("About to send final bit\n");
|
||||||
|
net_send_stream(obj->c, response, strlen(response) + 1, coroutine_iter_sent, &nb);
|
||||||
|
nb->extra = obj;
|
||||||
|
printf("Done sending final bit\n");
|
||||||
|
lua_pop(L,lua_gettop(L));
|
||||||
|
printf("Poped everything\n");
|
||||||
|
return (KORE_RESULT_OK);
|
||||||
|
}else{
|
||||||
|
printf("Coroutine used for response returned something that was not a string:%s\n",lua_typename(L,lua_type(L,-1)));
|
||||||
|
return (KORE_RESULT_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
coroutine_disconnect(struct connection *c){
|
||||||
|
printf("Disconnect routine called\n");
|
||||||
|
struct co_obj *obj = (struct co_obj*)c->hdlr_extra;
|
||||||
|
lua_State *L = obj->L;
|
||||||
|
int ref = obj->ref;
|
||||||
|
luaL_unref(L,LUA_REGISTRYINDEX,ref);
|
||||||
|
free(obj);
|
||||||
|
printf("Done with disconnect\n");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
The coroutine passed to this function should yield() the data to send to the
|
||||||
|
client, then return when done.
|
||||||
|
|
||||||
|
http_response_co(request::userdata, co::coroutine)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lhttp_response_co(lua_State *L){
|
||||||
|
printf("Start response coroutine\n");
|
||||||
|
int coroutine_ref = luaL_ref(L,LUA_REGISTRYINDEX);
|
||||||
|
struct http_request *req = luaL_checkrequest(L,-1);
|
||||||
|
lua_pop(L,1);
|
||||||
|
req->flags |= HTTP_REQUEST_NO_CONTENT_LENGTH;
|
||||||
|
struct co_obj *obj = (struct co_obj*)malloc(sizeof(struct co_obj));
|
||||||
|
obj->L = lua_newthread(L);
|
||||||
|
obj->ref = coroutine_ref;
|
||||||
|
obj->c = req->owner;
|
||||||
|
obj->c->flags |= CONN_IS_BUSY;
|
||||||
|
obj->c->disconnect = coroutine_disconnect;
|
||||||
|
obj->c->hdlr_extra = obj;
|
||||||
|
printf("About to call iter next\n");
|
||||||
|
http_response(req,200,NULL,0);
|
||||||
|
coroutine_iter_next(obj);
|
||||||
|
printf("Done calling iter next\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
http_method_text(request::userdata)::string
|
http_method_text(request::userdata)::string
|
||||||
*/
|
*/
|
||||||
|
@ -278,6 +429,27 @@ lhttp_file_get(lua_State *L){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
http_set_flags(request::userdata, flags::number)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lhttp_set_flags(lua_State *L){
|
||||||
|
int flags = luaL_checkint(L,-1);
|
||||||
|
struct http_request *req = luaL_checkrequest(L,-2);
|
||||||
|
lua_pop(L,2);
|
||||||
|
req->flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
http_get_flags(request::userdata) :: number
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lhttp_get_flags(lua_State *L){
|
||||||
|
struct http_request *req = luaL_checkrequest(L,-1);
|
||||||
|
lua_pop(L,1);
|
||||||
|
lua_pushnumber(L,req->flags);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
log(priority::integer,message::string) //formating must be done before calling
|
log(priority::integer,message::string) //formating must be done before calling
|
||||||
*/
|
*/
|
||||||
|
@ -292,6 +464,7 @@ lkore_log(lua_State *L){
|
||||||
|
|
||||||
static const luaL_Reg kore_funcs[] = {
|
static const luaL_Reg kore_funcs[] = {
|
||||||
{"http_response", lhttp_response},
|
{"http_response", lhttp_response},
|
||||||
|
{"http_response_co", lhttp_response_co},
|
||||||
{"http_response_header", lhttp_response_header},
|
{"http_response_header", lhttp_response_header},
|
||||||
{"http_request_header", lhttp_request_header},
|
{"http_request_header", lhttp_request_header},
|
||||||
{"http_method_text",lhttp_method_text},
|
{"http_method_text",lhttp_method_text},
|
||||||
|
@ -306,6 +479,8 @@ static const luaL_Reg kore_funcs[] = {
|
||||||
{"http_populate_cookies",lhttp_populate_cookies},
|
{"http_populate_cookies",lhttp_populate_cookies},
|
||||||
{"http_populate_multipart_form",lhttp_populate_multipart_form},
|
{"http_populate_multipart_form",lhttp_populate_multipart_form},
|
||||||
{"http_file_get",lhttp_file_get},
|
{"http_file_get",lhttp_file_get},
|
||||||
|
{"http_set_flags",lhttp_set_flags},
|
||||||
|
{"http_get_flags",lhttp_get_flags},
|
||||||
{"log",lkore_log},
|
{"log",lkore_log},
|
||||||
{NULL,NULL}
|
{NULL,NULL}
|
||||||
};
|
};
|
||||||
|
@ -334,6 +509,15 @@ load_kore_libs(lua_State *L){
|
||||||
LUA_PUSH_CONST(L,LOG_INFO);
|
LUA_PUSH_CONST(L,LOG_INFO);
|
||||||
LUA_PUSH_CONST(L,LOG_DEBUG);
|
LUA_PUSH_CONST(L,LOG_DEBUG);
|
||||||
|
|
||||||
|
//Push flags for use with http_set_flags()
|
||||||
|
LUA_PUSH_CONST(L,HTTP_REQUEST_COMPLETE);
|
||||||
|
LUA_PUSH_CONST(L,HTTP_REQUEST_DELETE);
|
||||||
|
LUA_PUSH_CONST(L,HTTP_REQUEST_SLEEPING);
|
||||||
|
LUA_PUSH_CONST(L,HTTP_REQUEST_EXPECT_BODY);
|
||||||
|
LUA_PUSH_CONST(L,HTTP_REQUEST_RETAIN_EXTRA);
|
||||||
|
LUA_PUSH_CONST(L,HTTP_REQUEST_NO_CONTENT_LENGTH);
|
||||||
|
LUA_PUSH_CONST(L,HTTP_REQUEST_AUTHED);
|
||||||
|
|
||||||
//Set a global variable "PRODUCTION" true or false
|
//Set a global variable "PRODUCTION" true or false
|
||||||
#ifdef BUILD_PROD
|
#ifdef BUILD_PROD
|
||||||
lua_pushboolean(L,1);
|
lua_pushboolean(L,1);
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
|
|
||||||
|
struct co_obj {
|
||||||
|
lua_State *L;
|
||||||
|
int ref;
|
||||||
|
struct connection *c;
|
||||||
|
};
|
||||||
int lhttp_response(lua_State *L);
|
int lhttp_response(lua_State *L);
|
||||||
|
int coroutine_iter_sent(struct netbuf *buf);
|
||||||
|
int coroutine_iter_next(struct co_obj *obj);
|
||||||
int lhttp_response_header(lua_State *L);
|
int lhttp_response_header(lua_State *L);
|
||||||
int lhttp_method_text(lua_State *L);
|
int lhttp_method_text(lua_State *L);
|
||||||
int lhttp_request_get_path(lua_State *L);
|
int lhttp_request_get_path(lua_State *L);
|
||||||
|
|
|
@ -5,4 +5,5 @@ A one-stop-shop for runtime configuration
|
||||||
return {
|
return {
|
||||||
domain = "<{get domain}>",
|
domain = "<{get domain}>",
|
||||||
production = false,
|
production = false,
|
||||||
|
legacy_url_cutoff = 144
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,55 @@
|
||||||
local function archive(req)
|
local function archive(req)
|
||||||
local archive = assert(io.open("data/archive.zip","r"))
|
local archive = assert(io.open("data/archive.zip","rb"))
|
||||||
http_response_header(req,"Content-Type","application/zip")
|
--[=[
|
||||||
|
local archive_size = archive:seek("end")
|
||||||
|
archive:seek("set")
|
||||||
|
local archive_cursor = 0
|
||||||
|
local co = coroutine.create(function()
|
||||||
|
print("Inside coroutine!")
|
||||||
|
--[[
|
||||||
|
for i = 1,10 do
|
||||||
|
local str = {tostring(i),":",}
|
||||||
|
for i = 1,10 do
|
||||||
|
table.insert(str,tostring(math.random()))
|
||||||
|
end
|
||||||
|
coroutine.yield(table.concat(str))
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
for i = 1, 1000 do
|
||||||
|
coroutine.yield("Hello, world!" .. tostring(i))
|
||||||
|
end
|
||||||
|
--[[
|
||||||
|
while archive_cursor ~= archive_size do
|
||||||
|
print("Inside while")
|
||||||
|
local bytes_left = archive_size - archive_cursor
|
||||||
|
local next_chunk = math.min(4096,bytes_left)
|
||||||
|
print("Before yield")
|
||||||
|
coroutine.yield(archive:read(next_chunk))
|
||||||
|
print("After yield")
|
||||||
|
end
|
||||||
|
archive:close()
|
||||||
|
]]
|
||||||
|
end)
|
||||||
|
print("co status:",coroutine.status(co))
|
||||||
|
--local bytes_start,bytes_end = 0, 200
|
||||||
|
--http_response_header(req,"content-type","application/zip")
|
||||||
|
--http_response_header(req,"accept-ranges","bytes")
|
||||||
|
http_response_header(req,"transfer-encoding","chunked")
|
||||||
|
http_response_co(req,co)
|
||||||
|
print("a print after our response")
|
||||||
|
--[[
|
||||||
|
local bytes_start,bytes_end = 0, 200
|
||||||
|
http_response_header(req,"content-type","application/zip")
|
||||||
|
http_response_header(req,"accept-ranges","bytes")
|
||||||
|
assert(archive:seek("set",bytes_start))
|
||||||
|
local data = assert(archive:read(bytes_end - bytes_start))
|
||||||
|
http_response_stream(req,200,data,function()
|
||||||
|
print("Callback completed!")
|
||||||
|
end)
|
||||||
|
]]
|
||||||
|
]=]
|
||||||
http_response_header(req,"Content-Disposition","attachment; filename=\"slash_monster_archive.zip\"")
|
http_response_header(req,"Content-Disposition","attachment; filename=\"slash_monster_archive.zip\"")
|
||||||
http_response(req,200,archive:read("*a"))
|
http_response(req,200,archive:read("*a"))
|
||||||
|
archive:close()
|
||||||
end
|
end
|
||||||
return archive
|
return archive
|
||||||
|
|
|
@ -17,6 +17,7 @@ local pagenames = {
|
||||||
"author_paste",
|
"author_paste",
|
||||||
"author_edit",
|
"author_edit",
|
||||||
"search",
|
"search",
|
||||||
|
"error",
|
||||||
}
|
}
|
||||||
local pages = {}
|
local pages = {}
|
||||||
for k,v in pairs(pagenames) do
|
for k,v in pairs(pagenames) do
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
local sql = require("lsqlite3")
|
local sql = require("lsqlite3")
|
||||||
|
local config = require("config")
|
||||||
local util = {}
|
local util = {}
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
@ -84,10 +85,18 @@ local url_characters =
|
||||||
[[ABCDEFGHIJKLMNOPQRSTUVWXYZ]]..
|
[[ABCDEFGHIJKLMNOPQRSTUVWXYZ]]..
|
||||||
[[0123456789]]
|
[[0123456789]]
|
||||||
|
|
||||||
|
local url_characters_legacy =
|
||||||
|
url_characters ..
|
||||||
|
[[$-+!*'(),]]
|
||||||
|
|
||||||
local url_characters_rev = {}
|
local url_characters_rev = {}
|
||||||
for i = 1,string.len(url_characters) do
|
for i = 1,string.len(url_characters) do
|
||||||
url_characters_rev[string.sub(url_characters,i,i)] = i
|
url_characters_rev[string.sub(url_characters,i,i)] = i
|
||||||
end
|
end
|
||||||
|
local url_characters_rev_legacy = {}
|
||||||
|
for i = 1,string.len(url_characters_legacy) do
|
||||||
|
url_characters_rev_legacy[string.sub(url_characters_legacy,i,i)] = i
|
||||||
|
end
|
||||||
--[[
|
--[[
|
||||||
Encode a number to a shorter HTML-safe url path
|
Encode a number to a shorter HTML-safe url path
|
||||||
]]
|
]]
|
||||||
|
@ -117,6 +126,7 @@ function util.decode_id(s)
|
||||||
return n
|
return n
|
||||||
end)
|
end)
|
||||||
if res then
|
if res then
|
||||||
|
print("returning id:",id)
|
||||||
return id
|
return id
|
||||||
else
|
else
|
||||||
print("Failed to decode id:" .. s)
|
print("Failed to decode id:" .. s)
|
||||||
|
@ -124,6 +134,32 @@ function util.decode_id(s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Legacy code, try to decode with invalid characters in the url first
|
||||||
|
]]
|
||||||
|
local new_decode = util.decode_id
|
||||||
|
function util.decode_id(s)
|
||||||
|
local res, id = pcall(function()
|
||||||
|
local n = 0
|
||||||
|
local charlen = string.len(url_characters_legacy)
|
||||||
|
for i = 1,string.len(s) do
|
||||||
|
local char = string.sub(s,i,i)
|
||||||
|
local pos = url_characters_rev_legacy[char] - 1
|
||||||
|
n = n + (pos * math.pow(charlen,i-1))
|
||||||
|
end
|
||||||
|
return n
|
||||||
|
end)
|
||||||
|
if res then
|
||||||
|
if id > config.legacy_url_cutoff then
|
||||||
|
return new_decode(s)
|
||||||
|
else
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false,"Failed to decode id:" .. s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--arbitary data to hex encoded string
|
--arbitary data to hex encoded string
|
||||||
function util.encode_unlisted(str)
|
function util.encode_unlisted(str)
|
||||||
assert(type(str) == "string","Tried to encode something not a string:" .. type(Str))
|
assert(type(str) == "string","Tried to encode something not a string:" .. type(Str))
|
||||||
|
|
Loading…
Reference in New Issue