mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-04-18 12:54:49 +00:00
Support redbean Fetch() headers (#405)
This commit is contained in:
parent
cfc3a953ae
commit
70c97f598b
2 changed files with 59 additions and 11 deletions
|
@ -682,23 +682,26 @@ FUNCTIONS
|
||||||
EscapeUser(str) → str
|
EscapeUser(str) → str
|
||||||
Escapes URL username. See kescapeauthority.c.
|
Escapes URL username. See kescapeauthority.c.
|
||||||
|
|
||||||
Fetch(url:str[,body:str|{method=value:str,body=value:str,...}])
|
Fetch(url:str[,body:str|{method=value:str,body=value:str,headers=table,...}])
|
||||||
→ status:int,{header:str=value:str,...},body:str
|
→ status:int,{header:str=value:str,...},body:str
|
||||||
Sends an HTTP/HTTPS request to the specified URL. If only the URL is
|
Sends an HTTP/HTTPS request to the specified URL. If only the URL is
|
||||||
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 as well other
|
the second value allows setting request method, body, and headers, as
|
||||||
options:
|
well as some other options:
|
||||||
- method (default = "GET"): sets the method to be used for the
|
- method (default = "GET"): sets the method to be used for the
|
||||||
request. The specified method is converted to uppercase.
|
request. The specified method is converted to uppercase.
|
||||||
- body (default = ""): sets the body value to be sent.
|
- body (default = ""): sets the body value to be sent.
|
||||||
|
- headers: sets headers for the request using the key/value pairs
|
||||||
|
from this table. Only string keys are used and all the values are
|
||||||
|
converted to strings.
|
||||||
- followredirect (default = true): forces temporary and permanent
|
- followredirect (default = true): forces temporary and permanent
|
||||||
redirects to be followed. This behavior can be disabled by
|
redirects to be followed. This behavior can be disabled by
|
||||||
passing `false`.
|
passing `false`.
|
||||||
- maxredirects (default = 5): sets the number of allowed redirects
|
- maxredirects (default = 5): sets the number of allowed redirects
|
||||||
to minimize looping due to misconfigured servers. When the number
|
to minimize looping due to misconfigured servers. When the number
|
||||||
is exceeded, the result of the last redirect is returned.
|
is exceeded, the last response is returned.
|
||||||
When the redirect is being followed, the same method and body values
|
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
|
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
|
that case the method is set to GET and the body is removed before the
|
||||||
|
|
|
@ -3685,7 +3685,7 @@ static int LuaFetch(lua_State *L) {
|
||||||
bool usessl;
|
bool usessl;
|
||||||
uint32_t ip;
|
uint32_t ip;
|
||||||
struct Url url;
|
struct Url url;
|
||||||
int t, ret, sock, methodidx;
|
int t, ret, sock, methodidx, hdridx;
|
||||||
char *host, *port;
|
char *host, *port;
|
||||||
struct TlsBio *bio;
|
struct TlsBio *bio;
|
||||||
struct addrinfo *addr;
|
struct addrinfo *addr;
|
||||||
|
@ -3694,6 +3694,11 @@ static int LuaFetch(lua_State *L) {
|
||||||
struct HttpUnchunker u;
|
struct HttpUnchunker u;
|
||||||
const char *urlarg, *request, *body, *method;
|
const char *urlarg, *request, *body, *method;
|
||||||
char *conlenhdr = "";
|
char *conlenhdr = "";
|
||||||
|
char *headers = 0;
|
||||||
|
char *hosthdr = 0;
|
||||||
|
char *agenthdr = brand;
|
||||||
|
char *key, *val, *hdr;
|
||||||
|
size_t keylen, vallen;
|
||||||
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;
|
int numredirects = 0, maxredirects = 5;
|
||||||
|
@ -3720,6 +3725,43 @@ static int LuaFetch(lua_State *L) {
|
||||||
maxredirects = luaL_optinteger(L, -1, maxredirects);
|
maxredirects = luaL_optinteger(L, -1, maxredirects);
|
||||||
lua_getfield(L, 2, "numredirects");
|
lua_getfield(L, 2, "numredirects");
|
||||||
numredirects = luaL_optinteger(L, -1, numredirects);
|
numredirects = luaL_optinteger(L, -1, numredirects);
|
||||||
|
lua_getfield(L, 2, "headers");
|
||||||
|
if (!lua_isnil(L, -1)) {
|
||||||
|
if (!lua_istable(L, -1))
|
||||||
|
return luaL_argerror(L, 2, "invalid headers value; table expected");
|
||||||
|
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, -2)) {
|
||||||
|
if (lua_type(L, -2) == LUA_TSTRING) { // skip any non-string keys
|
||||||
|
key = lua_tolstring(L, -2, &keylen);
|
||||||
|
if (!IsValidHttpToken(key, keylen))
|
||||||
|
return luaL_argerror(L, 2, "invalid header name");
|
||||||
|
|
||||||
|
val = lua_tolstring(L, -1, &vallen);
|
||||||
|
if (!(hdr = gc(EncodeHttpHeaderValue(val, vallen, 0))))
|
||||||
|
return luaL_argerror(L, 2, "invalid header value encoding");
|
||||||
|
|
||||||
|
// Content-Length and Connection will be overwritten;
|
||||||
|
// skip them to avoid duplicates;
|
||||||
|
// also allow unknown headers
|
||||||
|
if ((hdridx = GetHttpHeader(key, keylen)) == -1 ||
|
||||||
|
hdridx != kHttpContentLength &&
|
||||||
|
hdridx != kHttpConnection) {
|
||||||
|
if (hdridx == kHttpUserAgent) {
|
||||||
|
agenthdr = hdr;
|
||||||
|
} else if (hdridx == kHttpHost) {
|
||||||
|
hosthdr = hdr;
|
||||||
|
} else {
|
||||||
|
appendd(&headers, key, keylen);
|
||||||
|
appendw(&headers, READ16LE(": "));
|
||||||
|
appends(&headers, hdr);
|
||||||
|
appendw(&headers, READ16LE("\r\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(L, 1); // pop the value, keep the key for the next iteration
|
||||||
|
}
|
||||||
|
}
|
||||||
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 = "";
|
||||||
|
@ -3765,15 +3807,18 @@ static int LuaFetch(lua_State *L) {
|
||||||
port = usessl ? "443" : "80";
|
port = usessl ? "443" : "80";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ip = ntohl(servers.p[0].addr.sin_addr.s_addr);
|
ip = servers.n ? ntohl(servers.p[0].addr.sin_addr.s_addr) : INADDR_LOOPBACK;
|
||||||
host =
|
host =
|
||||||
gc(xasprintf("%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16, ip >> 8, ip));
|
gc(xasprintf("%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16, ip >> 8, ip));
|
||||||
port = gc(xasprintf("%d", ntohs(servers.p[0].addr.sin_port)));
|
port =
|
||||||
|
gc(xasprintf("%d", servers.n ? ntohs(servers.p[0].addr.sin_port) : 80));
|
||||||
}
|
}
|
||||||
if (!IsAcceptableHost(host, -1)) {
|
if (!IsAcceptableHost(host, -1)) {
|
||||||
luaL_argerror(L, 1, "invalid host");
|
luaL_argerror(L, 1, "invalid host");
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
if (!hosthdr) hosthdr = gc(xasprintf("%s:%s", host, port));
|
||||||
|
|
||||||
url.fragment.p = 0, url.fragment.n = 0;
|
url.fragment.p = 0, url.fragment.n = 0;
|
||||||
url.scheme.p = 0, url.scheme.n = 0;
|
url.scheme.p = 0, url.scheme.n = 0;
|
||||||
url.user.p = 0, url.user.n = 0;
|
url.user.p = 0, url.user.n = 0;
|
||||||
|
@ -3791,13 +3836,13 @@ static int LuaFetch(lua_State *L) {
|
||||||
* Create HTTP message.
|
* Create HTTP message.
|
||||||
*/
|
*/
|
||||||
request = gc(xasprintf("%s %s HTTP/1.1\r\n"
|
request = gc(xasprintf("%s %s HTTP/1.1\r\n"
|
||||||
"Host: %s:%s\r\n"
|
"Host: %s\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"User-Agent: %s\r\n"
|
"User-Agent: %s\r\n"
|
||||||
"%s"
|
"%s%s"
|
||||||
"\r\n%s",
|
"\r\n%s",
|
||||||
method, gc(EncodeUrl(&url, 0)), host, port, brand,
|
method, gc(EncodeUrl(&url, 0)), hosthdr, agenthdr,
|
||||||
conlenhdr, body));
|
conlenhdr, headers ? headers : "", body));
|
||||||
requestlen = strlen(request);
|
requestlen = strlen(request);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Reference in a new issue