Update redbean GetResponseBody to take response compression into account (#561)

This commit is contained in:
Paul Kulchenko 2022-08-21 22:26:41 -07:00 committed by GitHub
parent e204fc0820
commit 04cd62c319
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 8 deletions

View file

@ -1067,9 +1067,13 @@ FUNCTIONS
IsPrivateIp or IsLoopbackIp return true. When multiple addresses IsPrivateIp or IsLoopbackIp return true. When multiple addresses
are present in the header, the last/right-most address is used. are present in the header, the last/right-most address is used.
GetResponseBody() → str GetResponseBody()
Returns the response message body if present or an empty string. ├─→ body:str
Also returns an empty string during streaming. └─→ nil, error:str
Returns the (uncompressed) response message body if present or an
empty string. May also return a partial or empty string during
streaming, as the full content may not be known at the call time.
Returns an error when decompression fails.
GetClientAddr() → ip:uint32,port:uint16 GetClientAddr() → ip:uint32,port:uint16
Returns client socket ip4 address and port, e.g. 0x01020304,31337 Returns client socket ip4 address and port, e.g. 0x01020304,31337

View file

@ -356,7 +356,6 @@ typedef ssize_t (*writer_f)(int, struct iovec *, int);
struct ClearedPerMessage { struct ClearedPerMessage {
bool istext; bool istext;
bool gzipped;
bool branded; bool branded;
bool hascontenttype; bool hascontenttype;
bool gotcachecontrol; bool gotcachecontrol;
@ -366,6 +365,7 @@ struct ClearedPerMessage {
int isyielding; int isyielding;
char *outbuf; char *outbuf;
char *content; char *content;
size_t gzipped;
size_t contentlength; size_t contentlength;
char *luaheaderp; char *luaheaderp;
const char *referrerpolicy; const char *referrerpolicy;
@ -2336,7 +2336,7 @@ static char *CommitOutput(char *p) {
p = stpcpy(p, "Vary: Accept-Encoding\r\n"); p = stpcpy(p, "Vary: Accept-Encoding\r\n");
} }
if (!IsTiny() && !IsSslCompressed() && ClientAcceptsGzip()) { if (!IsTiny() && !IsSslCompressed() && ClientAcceptsGzip()) {
cpm.gzipped = true; cpm.gzipped = outbuflen;
crc = crc32_z(0, cpm.outbuf, outbuflen); crc = crc32_z(0, cpm.outbuf, outbuflen);
WRITE32LE(gzip_footer + 0, crc); WRITE32LE(gzip_footer + 0, crc);
WRITE32LE(gzip_footer + 4, outbuflen); WRITE32LE(gzip_footer + 4, outbuflen);
@ -2568,7 +2568,7 @@ static char *ServeAssetCompressed(struct Asset *a) {
} else { } else {
dg.z = 65536; dg.z = 65536;
} }
cpm.gzipped = true; cpm.gzipped = -1; // signal generator usage with the exact size unknown
cpm.generator = DeflateGenerator; cpm.generator = DeflateGenerator;
bzero(&dg.s, sizeof(dg.s)); bzero(&dg.s, sizeof(dg.s));
CHECK_EQ(Z_OK, deflateInit2(&dg.s, 4, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, CHECK_EQ(Z_OK, deflateInit2(&dg.s, 4, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL,
@ -2661,9 +2661,9 @@ static inline char *ServeAssetPrecompressed(struct Asset *a) {
uint32_t crc; uint32_t crc;
DEBUGF("(srvr) ServeAssetPrecompressed()"); DEBUGF("(srvr) ServeAssetPrecompressed()");
LockInc(&shared->c.precompressedresponses); LockInc(&shared->c.precompressedresponses);
cpm.gzipped = true;
crc = ZIP_CFILE_CRC32(zbase + a->cf); crc = ZIP_CFILE_CRC32(zbase + a->cf);
size = GetZipCfileUncompressedSize(zbase + a->cf); size = GetZipCfileUncompressedSize(zbase + a->cf);
cpm.gzipped = size;
WRITE32LE(gzip_footer + 0, crc); WRITE32LE(gzip_footer + 0, crc);
WRITE32LE(gzip_footer + 4, size); WRITE32LE(gzip_footer + 4, size);
return SetStatus(200, "OK"); return SetStatus(200, "OK");
@ -3988,8 +3988,18 @@ static int LuaGetBody(lua_State *L) {
} }
static int LuaGetResponseBody(lua_State *L) { static int LuaGetResponseBody(lua_State *L) {
char *s = "";
// response can be gzipped (>0), text (=0), or generator (<0)
int size = cpm.gzipped > 0 ? cpm.gzipped // original size
: cpm.gzipped == 0 ? cpm.contentlength : 0;
OnlyCallDuringRequest(L, "GetResponseBody"); OnlyCallDuringRequest(L, "GetResponseBody");
lua_pushlstring(L, cpm.content, cpm.contentlength); if (cpm.gzipped > 0 &&
(!(s = FreeLater(malloc(cpm.gzipped))) ||
!Inflate(s, cpm.gzipped, cpm.content, cpm.contentlength))) {
return LuaNilError(L, "failed to decompress response");
}
lua_pushlstring(L, cpm.gzipped > 0 ? s // return decompressed
: cpm.gzipped == 0 ? cpm.content : "", size);
return 1; return 1;
} }