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 <inet/in.h>//linux only I guess
|
||||
#include "libkore.h"
|
||||
#include "smr.h" //Where the error handler code is
|
||||
#include <syslog.h>
|
||||
|
||||
#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
|
||||
lhttp_response(lua_State *L){
|
||||
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);
|
||||
struct http_request *req = luaL_checkrequest(L,-3);
|
||||
http_response(req,httpcode,data,size);
|
||||
|
@ -38,6 +45,150 @@ lhttp_response(lua_State *L){
|
|||
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
|
||||
*/
|
||||
|
@ -278,6 +429,27 @@ lhttp_file_get(lua_State *L){
|
|||
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
|
||||
*/
|
||||
|
@ -292,6 +464,7 @@ lkore_log(lua_State *L){
|
|||
|
||||
static const luaL_Reg kore_funcs[] = {
|
||||
{"http_response", lhttp_response},
|
||||
{"http_response_co", lhttp_response_co},
|
||||
{"http_response_header", lhttp_response_header},
|
||||
{"http_request_header", lhttp_request_header},
|
||||
{"http_method_text",lhttp_method_text},
|
||||
|
@ -306,6 +479,8 @@ static const luaL_Reg kore_funcs[] = {
|
|||
{"http_populate_cookies",lhttp_populate_cookies},
|
||||
{"http_populate_multipart_form",lhttp_populate_multipart_form},
|
||||
{"http_file_get",lhttp_file_get},
|
||||
{"http_set_flags",lhttp_set_flags},
|
||||
{"http_get_flags",lhttp_get_flags},
|
||||
{"log",lkore_log},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
@ -334,6 +509,15 @@ load_kore_libs(lua_State *L){
|
|||
LUA_PUSH_CONST(L,LOG_INFO);
|
||||
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
|
||||
#ifdef BUILD_PROD
|
||||
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 coroutine_iter_sent(struct netbuf *buf);
|
||||
int coroutine_iter_next(struct co_obj *obj);
|
||||
int lhttp_response_header(lua_State *L);
|
||||
int lhttp_method_text(lua_State *L);
|
||||
int lhttp_request_get_path(lua_State *L);
|
||||
|
|
|
@ -5,4 +5,5 @@ A one-stop-shop for runtime configuration
|
|||
return {
|
||||
domain = "<{get domain}>",
|
||||
production = false,
|
||||
legacy_url_cutoff = 144
|
||||
}
|
||||
|
|
|
@ -1,7 +1,55 @@
|
|||
local function archive(req)
|
||||
local archive = assert(io.open("data/archive.zip","r"))
|
||||
http_response_header(req,"Content-Type","application/zip")
|
||||
local archive = assert(io.open("data/archive.zip","rb"))
|
||||
--[=[
|
||||
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(req,200,archive:read("*a"))
|
||||
archive:close()
|
||||
end
|
||||
return archive
|
||||
|
|
|
@ -17,6 +17,7 @@ local pagenames = {
|
|||
"author_paste",
|
||||
"author_edit",
|
||||
"search",
|
||||
"error",
|
||||
}
|
||||
local pages = {}
|
||||
for k,v in pairs(pagenames) do
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
local sql = require("lsqlite3")
|
||||
local config = require("config")
|
||||
local util = {}
|
||||
|
||||
--[[
|
||||
|
@ -84,10 +85,18 @@ local url_characters =
|
|||
[[ABCDEFGHIJKLMNOPQRSTUVWXYZ]]..
|
||||
[[0123456789]]
|
||||
|
||||
local url_characters_legacy =
|
||||
url_characters ..
|
||||
[[$-+!*'(),]]
|
||||
|
||||
local url_characters_rev = {}
|
||||
for i = 1,string.len(url_characters) do
|
||||
url_characters_rev[string.sub(url_characters,i,i)] = i
|
||||
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
|
||||
]]
|
||||
|
@ -117,6 +126,7 @@ function util.decode_id(s)
|
|||
return n
|
||||
end)
|
||||
if res then
|
||||
print("returning id:",id)
|
||||
return id
|
||||
else
|
||||
print("Failed to decode id:" .. s)
|
||||
|
@ -124,6 +134,32 @@ function util.decode_id(s)
|
|||
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
|
||||
function util.encode_unlisted(str)
|
||||
assert(type(str) == "string","Tried to encode something not a string:" .. type(Str))
|
||||
|
|
Loading…
Reference in New Issue