mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-04 18:28:30 +00:00
Add following redirects to redbean Fetch (#226)
This commit is contained in:
parent
fd76fa0016
commit
b142ea7176
2 changed files with 63 additions and 9 deletions
|
@ -545,7 +545,19 @@ FUNCTIONS
|
||||||
provided, then a GET request is sent. If both URL and body parameters
|
provided, then a GET request is sent. If both URL and body parameters
|
||||||
are specified, then a POST request is sent. If any other method needs
|
are specified, then a POST request is sent. If any other method needs
|
||||||
to be specified (for example, PUT or DELETE), then passing a table as
|
to be specified (for example, PUT or DELETE), then passing a table as
|
||||||
the second value allows setting method and body values.
|
the second value allows setting method and body values as well other
|
||||||
|
options:
|
||||||
|
- followredirect (default = true): forces temporary and permanent
|
||||||
|
redirects to be followed. This behavior can be disabled by
|
||||||
|
passing `false`.
|
||||||
|
- maxredirects (default = 5): sets the number of allowed redirects
|
||||||
|
to minimize looping due to misconfigured servers. When the number
|
||||||
|
is exceeded, the result of the last redirect is returned.
|
||||||
|
When the redirect is being followed, the same method and body values
|
||||||
|
are being sent in all cases except when 303 status is returned. In
|
||||||
|
that case the method is set to GET and the body is removed before the
|
||||||
|
redirect is followed. Note that if these (method/body) values are
|
||||||
|
provided as table fields, they will be modified in place.
|
||||||
|
|
||||||
FormatHttpDateTime(seconds:int) → rfc1123:str
|
FormatHttpDateTime(seconds:int) → rfc1123:str
|
||||||
Converts UNIX timestamp to an RFC1123 string that looks like this:
|
Converts UNIX timestamp to an RFC1123 string that looks like this:
|
||||||
|
|
|
@ -3703,6 +3703,8 @@ static int LuaFetch(lua_State *L) {
|
||||||
char *conlenhdr = "";
|
char *conlenhdr = "";
|
||||||
size_t urlarglen, requestlen, paylen, bodylen;
|
size_t urlarglen, requestlen, paylen, bodylen;
|
||||||
size_t g, i, n, hdrsize;
|
size_t g, i, n, hdrsize;
|
||||||
|
int numredirects = 0, maxredirects = 5;
|
||||||
|
bool followredirect = true;
|
||||||
struct addrinfo hints = {.ai_family = AF_INET,
|
struct addrinfo hints = {.ai_family = AF_INET,
|
||||||
.ai_socktype = SOCK_STREAM,
|
.ai_socktype = SOCK_STREAM,
|
||||||
.ai_protocol = IPPROTO_TCP,
|
.ai_protocol = IPPROTO_TCP,
|
||||||
|
@ -3719,6 +3721,12 @@ static int LuaFetch(lua_State *L) {
|
||||||
lua_getfield(L, 2, "method");
|
lua_getfield(L, 2, "method");
|
||||||
// use GET by default if no method is provided
|
// use GET by default if no method is provided
|
||||||
method = strtoupper(luaL_optstring(L, -1, kHttpMethod[kHttpGet]));
|
method = strtoupper(luaL_optstring(L, -1, kHttpMethod[kHttpGet]));
|
||||||
|
lua_getfield(L, 2, "followredirect");
|
||||||
|
if (lua_isboolean(L, -1)) followredirect = lua_toboolean(L, -1);
|
||||||
|
lua_getfield(L, 2, "maxredirects");
|
||||||
|
maxredirects = luaL_optinteger(L, -1, maxredirects);
|
||||||
|
lua_getfield(L, 2, "numredirects");
|
||||||
|
numredirects = luaL_optinteger(L, -1, numredirects);
|
||||||
lua_settop(L, 2); // drop all added elements to keep the stack balanced
|
lua_settop(L, 2); // drop all added elements to keep the stack balanced
|
||||||
} else if (lua_isnoneornil(L, 2)) {
|
} else if (lua_isnoneornil(L, 2)) {
|
||||||
body = "";
|
body = "";
|
||||||
|
@ -3995,8 +4003,41 @@ static int LuaFetch(lua_State *L) {
|
||||||
|
|
||||||
Finished:
|
Finished:
|
||||||
if (paylen && logbodies) LogBody("received", inbuf.p + hdrsize, paylen);
|
if (paylen && logbodies) LogBody("received", inbuf.p + hdrsize, paylen);
|
||||||
LOGF("FETCH HTTP%02d %d %s %`'.*s", msg.version, msg.status, urlarg,
|
LOGF("FETCH %s HTTP%02d %d %s %`'.*s", method, msg.version, msg.status, urlarg,
|
||||||
HeaderLength(kHttpServer), HeaderData(kHttpServer));
|
HeaderLength(kHttpServer), HeaderData(kHttpServer));
|
||||||
|
if (followredirect && HasHeader(kHttpLocation) &&
|
||||||
|
(msg.status == 301 || msg.status == 308 || // permanent redirects
|
||||||
|
msg.status == 302 || msg.status == 307 || // temporary redirects
|
||||||
|
msg.status == 303 // see other; non-GET changes to GET, body lost
|
||||||
|
) && numredirects < maxredirects) {
|
||||||
|
// if 303, then remove body and set method to GET
|
||||||
|
if (msg.status == 303) {
|
||||||
|
body = "";
|
||||||
|
bodylen = 0;
|
||||||
|
method = kHttpMethod[kHttpGet];
|
||||||
|
}
|
||||||
|
// create table if needed
|
||||||
|
if (!lua_istable(L, 2)) {
|
||||||
|
lua_settop(L, 1); // pop body if present
|
||||||
|
lua_createtable(L, 0, 3); // body, method, numredirects
|
||||||
|
}
|
||||||
|
lua_pushlstring(L, body, bodylen);
|
||||||
|
lua_setfield(L, -2, "body");
|
||||||
|
|
||||||
|
lua_pushstring(L, method);
|
||||||
|
lua_setfield(L, -2, "method");
|
||||||
|
|
||||||
|
lua_pushinteger(L, numredirects + 1);
|
||||||
|
lua_setfield(L, -2, "numredirects");
|
||||||
|
// replace URL with Location header
|
||||||
|
lua_pushlstring(L, HeaderData(kHttpLocation), HeaderLength(kHttpLocation));
|
||||||
|
lua_replace(L, -3);
|
||||||
|
|
||||||
|
DestroyHttpMessage(&msg);
|
||||||
|
free(inbuf.p);
|
||||||
|
close(sock);
|
||||||
|
return LuaFetch(L);
|
||||||
|
} else {
|
||||||
lua_pushinteger(L, msg.status);
|
lua_pushinteger(L, msg.status);
|
||||||
LuaPushHeaders(L, &msg, inbuf.p);
|
LuaPushHeaders(L, &msg, inbuf.p);
|
||||||
lua_pushlstring(L, inbuf.p + hdrsize, paylen);
|
lua_pushlstring(L, inbuf.p + hdrsize, paylen);
|
||||||
|
@ -4004,6 +4045,7 @@ Finished:
|
||||||
free(inbuf.p);
|
free(inbuf.p);
|
||||||
close(sock);
|
close(sock);
|
||||||
return 3;
|
return 3;
|
||||||
|
}
|
||||||
TransportError:
|
TransportError:
|
||||||
close(sock);
|
close(sock);
|
||||||
free(inbuf.p);
|
free(inbuf.p);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue