Skip to content

Instantly share code, notes, and snippets.

@mezzatto
Created August 11, 2016 17:02
Show Gist options
  • Save mezzatto/d9e09418f66bf6317ae0e700f3294b24 to your computer and use it in GitHub Desktop.
Save mezzatto/d9e09418f66bf6317ae0e700f3294b24 to your computer and use it in GitHub Desktop.
Read HTTPD request body
#include <strings.h>
#include <sys/types.h>
#include <unistd.h>
#include <zlib.h>
static long int uncompressedBytes(apr_pool_t* p, char** uncompressedData, const void* bytes, size_t length)
{
z_stream strm;
int ret;
unsigned char out[128 * 1024];
unsigned int uncompressedLength = 0;
*uncompressedData = NULL;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
if(inflateInit2(&strm, 40) != Z_OK)
return -1;
strm.avail_in = length;
strm.next_in = (void*)bytes;
do
{
strm.avail_out = sizeof(out);
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
if(ret != Z_OK && ret != Z_STREAM_END)
{
inflateEnd(&strm);
return -2;
}
unsigned int have = sizeof(out) - strm.avail_out;
if(*uncompressedData == NULL)
{
*uncompressedData = apr_palloc(p, have + 1);
memcpy(*uncompressedData, out, have);
uncompressedLength = have;
}
else
{
void* resizedUncompressedData = apr_palloc(p, uncompressedLength + have + 1);
memcpy(resizedUncompressedData, *uncompressedData, uncompressedLength);
*uncompressedData = resizedUncompressedData;
memcpy(*uncompressedData + uncompressedLength, out, have);
uncompressedLength += have;
}
} while(ret != Z_STREAM_END);
(*uncompressedData)[strm.total_out] = '\0';
inflateEnd(&strm);
return uncompressedLength;
}
static long int readRequestBody(request_rec* r, char** body)
{
*body = NULL;
if(ap_setup_client_block(r, REQUEST_CHUNKED_ERROR) != OK)
return -1;
if(ap_should_client_block(r) == 0)
return -2;
char buffer[64 * 1024];
unsigned int bodyLength = 0;
long int readLength;
long int bodySize = r->remaining;
if(bodySize > (16 << 20))
{
r->status = HTTP_REQUEST_ENTITY_TOO_LARGE;
return -3;
}
*body = malloc(bodySize + 1);
while((readLength = ap_get_client_block(r, buffer, sizeof(buffer))) > 0)
{
if(bodyLength + readLength > bodySize)
*body = realloc(*body, (bodySize = (bodyLength + readLength) << 1));
memcpy((char*)*body + bodyLength, buffer, readLength);
bodyLength += readLength;
}
(*body)[bodyLength] = '\0';
return bodyLength;
}
static apr_status_t getReturnFree(void* data)
{
free(data);
return APR_SUCCESS;
}
char* getRequestBody(request_rec* r)
{
char* body;
long int bodyLen;
if((bodyLen = readRequestBody(r, &body)) < 0)
return NULL;
apr_pool_cleanup_register(r->pool, body, getReturnFree, apr_pool_cleanup_null);
const char* const encoding = (char*)apr_table_get(r->headers_in, "Content-Encoding");
if(encoding && strcmp(encoding, "gzip") == 0)
{
char* uncompressed;
long int uncompressedLen;
if((uncompressedLen = uncompressedBytes(r->pool, &uncompressed, body, bodyLen)) < 0)
return NULL;
body = uncompressed;
}
return body;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment