mod_deflate always sends gzip data when the request header Accept-Encoding is gip, deflate.
How can I tell mod_deflate to prefer to send deflate (NOT zlib) instead of gzip?
If this isn't possible...why would the develpers name the module mod_deflate when it can't deflate. Also, what is the best way, if any, for me to submit a bug report to have this fixed in future releases?
After looking at the source code for mod_deflate I have come to the conclusion that it is impossible to send anything other than gzip.
Now, I'm not a c programmer and I don't think I'll be able to commit any patches myself...but from the source I can see that there are a few things that need to be fixed (warning, I've never written any c...so this is all probably terribly wrong)
/* add this method */
static const char *deflate_set_preferred_method(cmd_parms *cmd, void *dummy,
const char *arg1)
{
deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
&deflate_module);
if (arg2 != NULL && (!strcasecmp(arg1, "deflate") || !strcasecmp(arg1, "gzip") || !strcasecmp(arg1, "zlib") ) ) {
c->preferred_method = apr_pstrdup(cmd->pool, arg1);
}
else {
return apr_psprintf(cmd->pool, "Unknown preferred method type %s", arg1);
}
return NULL;
}
/* update some code to define "preferred_method" */
/*
Update all code that references the string "gzip" to take
into account "deflate", and "zlib" as well.
This is the part I really have no clue how to do.
lines: 539, 604, 607, 616, and 624 should be updates
line 624 could read something like this: */
if( !strcasecmp(preferred_method,"gzip") ){
/* add immortal gzip header */
e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header,
f->c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
}
else if( !strcasecmp(preferred_method, "zlib") ){
/* do something to add the zlib headers here */
}
/* update this method */
static const command_rec deflate_filter_cmds[] = {
AP_INIT_TAKE12("DeflateFilterNote", deflate_set_note, NULL, RSRC_CONF,
"Set a note to report on compression ratio"),
AP_INIT_TAKE1("DeflateWindowSize", deflate_set_window_size, NULL,
RSRC_CONF, "Set the Deflate window size (1-15)"),
AP_INIT_TAKE1("DeflateBufferSize", deflate_set_buffer_size, NULL, RSRC_CONF,
"Set the Deflate Buffer Size"),
AP_INIT_TAKE1("DeflateMemLevel", deflate_set_memlevel, NULL, RSRC_CONF,
"Set the Deflate Memory Level (1-9)"),
AP_INIT_TAKE1("DeflateCompressionLevel", deflate_set_compressionlevel, NULL, RSRC_CONF,
"Set the Deflate Compression Level (1-9)"),
AP_INIT_TAKE1("DeflatePreferredMethod", deflate_set_preferred_method, NULL, RSRC_CONF,
"Set the Preferred Compression Method: deflate, gzip, or zlib (not-recommended)"),
{NULL}
};
Related
I'm trying to do Apache performance benchmarking for my course project. But I meet a strange problem. When I use a single client to establish multiple TCP connections (e.g. 100) to an Apache server and send HTTP 1.1 requests with the Connection: keep-alive header, I suppose the TCP connections can be reused. But the Apache server will actively terminate TCP connections, even if Connection: Keep-Alive and Keep-Alive: xxx are included in the HTTP response header.
this is my client code (I obfuscate the IP address):
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
#define DEBUG
#define MAX_SOCKETS_NUM 100
#define BUF_LEN 4096
int main() {
int i;
struct sockaddr_in server_addr, peer_addr;
int res, len = sizeof(peer_addr);
char *req = "GET /20KB HTTP/1.1\r\n"
"Host: x.x.x.192\r\n"
"Connection: keep-alive\r\n"
"Upgrade-Insecure-Requests: 1\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"Accept-Language: zh-CN,zh;q=0.9\r\n"
"\r\n";
char buf[BUF_LEN + 1];
int sockets[MAX_SOCKETS_NUM];
int estb_num = 0;
int estb_map[MAX_SOCKETS_NUM];
struct timeval goal, now, interval;
// create sockets
for (i = 0; i < MAX_SOCKETS_NUM; i++) {
if ((sockets[i] = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0) {
printf("Socket %d error!\n", i);
return -1;
}
}
// initialize server_addr
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(80);
if (inet_pton(AF_INET, "x.x.x.192", &server_addr.sin_addr) <= 0) {
printf("Invalid address/Address not supported\n");
return -1;
}
// connect to the victim server
for (i = 0; i < MAX_SOCKETS_NUM; i++) {
if ((res = connect(sockets[i], (struct sockaddr *)&server_addr, sizeof(server_addr))) == 0) {
#ifdef DEBUG
printf("Socket %d connected immediately.\n", i);
#endif
estb_map[i] = 1;
estb_num++;
}
else if (res == -1) {
if (errno != EINPROGRESS) {
printf("Error occured when connect() is called on socket %d.\n", i);
return -1;
}
#ifdef DEBUG
printf("Socket %d sends SYN packet but the ACK is not received.\n", i);
#endif
}
}
while (1) {
if (estb_num == MAX_SOCKETS_NUM)
break;
for (i = 0; i < MAX_SOCKETS_NUM; i++) {
while (1) {
res = getpeername(sockets[i], (struct sockaddr *)&peer_addr, &len);
if (res == 0) {
estb_num++;
#ifdef DEBUG
printf("Socket %d connects successfully.\n", i);
#endif
break;
}
}
}
}
interval = (struct timeval) {
.tv_sec = 1,
.tv_usec = 0
};
len = strlen(req);
while (1) {
gettimeofday(&now, NULL);
timeradd(&now, &interval, &goal);
#ifdef DEBUG
printf("%ld.%ld\n", goal.tv_sec, goal.tv_usec);
#endif
// send requests
for (i = 0; i < MAX_SOCKETS_NUM; i++) {
res = send(sockets[i], req, len, 0);
if (res == -1) {
printf("socket:%ld errno:%ld\n", i, errno);
}
}
while (1) {
for (i = 0; i < MAX_SOCKETS_NUM; i++) {
res = recv(sockets[i], buf, BUF_LEN, 0);
if (res == 0) {
struct sockaddr_in dbg_addr;
int dgb_addr_len = sizeof(struct sockaddr_in);
getsockname(sockets[i], &dbg_addr, &dgb_addr_len);
printf("socket:%d port:%d\n", i, ntohs(dbg_addr.sin_port));
goto end;
}
else if (res == -1) {
if (errno != EAGAIN)
printf("Error occurs when recv is called.\n");
}
else {
// do nothing because we don't need the response
}
}
gettimeofday(&now, NULL);
if (timercmp(&now, &goal, >) != 0) {
#ifdef DEBUG
printf("%d.%d\n", now.tv_sec, now.tv_usec);
#endif
break;
}
}
}
end:
return 0;
}
the workflow of the client (with the IP address x.x.x.198) is:
establish 100 tcp connections to the server (with the IP address x.x.x.192) using non-blocking socket.
send the same requests on the 100 tcp connections
invoking non-blocking recv repeatedly on these 100 sockets for 1 second
goto 2.
one execution of the program generates the following output:
Socket 0 sends SYN packet but the ACK is not received.
(some lines are omitted)
Socket 99 sends SYN packet but the ACK is not received.
Socket 0 connects successfully.
(some lines are omitted)
Socket 99 connects successfully.
1639450192.343129
1639450192.343155
1639450193.343163
socket:63 port:56804
The output indicates in the second round of requests (the first round is finished because it prints two timestamps, but the second round only prints one), the recv function on the 63th socket with the local port number 56804 returns 0, which means the Apache server actively terminates tcp connections. And I dumped all the packets on the client using tcpdump, the following figure shows the packet trace of the connection with the local port number 56804:
the packet trace shows the same result that the server actively sends tcp FIN packet to the client to terminate the TCP connection. But we can see Connection: Keep-Alive and Keep-Alive: timeout=10m, max=1999 are included in the response header which means the Apache server handles keep-alive correctly.
The server runs Ubuntu 20.04.3 and Apache 2.4.41.
I's very confused about why this happens, why will Apache close keep-alive connections? I'd be appreciate if you can help me, thanks!
From this document:
A host MAY keep an idle connection open for longer than the time that
it indicates, but it SHOULD attempt to retain a connection for at
least as long as indicated.
Capital letters there are key, and written like this in the document:
Your case matches the "SHOULD" part. E.g. keep-alive is a recommendation - but if the server needs those resources (or is configured to have less open connections than the number of your clients) it's free to close them at will. Your clients will need to deal with this state.
If the described behavior is dependent on the number of parallel sockets that you open (apart from the timeout), you're most likely running into resource limits on your server - either explicitly configured, or implicit, from default values.
Imagine how easy a DDOS attack would be if all that's required was a couple of keep-alive requests to saturate the number of concurrent connections that the server offers.
Also note that timeout is based on different perceptions of time on server (starting with sending the last packet) and client (starting when receiving the last packet)
This question is a follow-up to "How are zlib, gzip and zip related? What do they have in common and how are they different?" The answers are very detailed but they never quite answer my specific question.
Given a valid GZIP file, should I always be able to extract the deflate-bytes inside and use those bytes to construct a valid PKZIP file with the same contents, without decompressing and recompressing that byte stream?
For example, imagine I have a collection of GZIP files. Could I write a program that quickly (by avoiding deflate/inflate) constructs an equivalent PKZIP file of those files by cutting the GZIP headers off the source files and building a PKZIP structure around the byte streams? (Also the same in reverse by taking any valid PKZIP file and quickly convert them into many GZIP files?)
Both file formats appear to use the same "deflate" algorithm, but is it exactly the same deflate algorithm?
Yes. It is exactly the same deflate format.
(The deflate algorithm can be, and in fact often is different, producing different deflate streams. However that is irrelevant to your application. The format is compatible, and any compliant inflator will be able to decompress the gzip deflate data transplanted into a zip file.)
I forgot why I wrote this, but the C code below will convert a gzip file to a single-entry zip file, with some constraints on the gzip file.
/*
gz2zip.c version 1.0, 31 July 2018
Copyright (C) 2018 Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Mark Adler
madler#alumni.caltech.edu
*/
// Convert gzip (.gz) file to a single entry zip file. See the comments before
// gz2zip() for more details and caveats.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
# include <fcntl.h>
# include <io.h>
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
# define SET_BINARY_MODE(file)
#endif
#define local static
// Exit on error.
local void bail(char *why) {
fprintf(stderr, "gz2zip abort: %s\n", why);
exit(1);
}
// Type to track number of bytes written.
typedef struct {
FILE *out;
off_t off;
} tally_t;
// Write len bytes at dat to t.
local void put(tally_t *t, void const *dat, size_t len) {
size_t ret = fwrite(dat, 1, len, t->out);
if (ret != len)
bail("write error");
t->off += len;
}
// Write 16-bit integer n in little-endian order to t.
local void put2(tally_t *t, unsigned n) {
unsigned char dat[2];
dat[0] = n;
dat[1] = n >> 8;
put(t, dat, 2);
}
// Write 32-bit integer n in little-endian order to t.
local void put4(tally_t *t, unsigned long n) {
put2(t, n);
put2(t, n >> 16);
}
// Write n zeros to t.
local void putz(tally_t *t, unsigned n) {
unsigned char const buf[1] = {0};
while (n--)
put(t, buf, 1);
}
// Convert the Unix time unix to DOS time in the four bytes at *dos. If there
// is a conversion error for any reason, store the current time in DOS format
// at *dos. The Unix time in seconds is rounded up to an even number of
// seconds, since the DOS time can only represent even seconds. If the Unix
// time is before 1980, the minimum DOS time of Jan 1, 1980 is used.
local void unix2dos(unsigned char *dos, time_t unix) {
unix += unix & 1;
struct tm *s = localtime(&unix);
if (s == NULL) {
unix = time(NULL); // on error, use current time
unix += unix & 1;
s = localtime(&unix);
if (s == NULL)
bail("internal error"); // shouldn't happen
}
if (s->tm_year < 80) { // no DOS time before 1980
dos[0] = 0; dos[1] = 0; // use midnight,
dos[2] = (1 << 5) + 1; dos[3] = 0; // Jan 1, 1980
}
else {
dos[0] = (s->tm_min << 5) + (s->tm_sec >> 1);
dos[1] = (s->tm_hour << 3) + (s->tm_min >> 3);
dos[2] = ((s->tm_mon + 1) << 5) + s->tm_mday;
dos[3] = ((s->tm_year - 80) << 1) + ((s->tm_mon + 1) >> 3);
}
}
// Chunk size for reading and writing raw deflate data.
#define CHUNK 16384
// Read the gzip file from in and write it as a single-entry zip file to out.
// This assumes that the gzip file has a single member, that it has no junk
// after the gzip trailer, and that it contains less than 4GB of uncompressed
// data. The gzip file is not decompressed or validated, other than checking
// for the proper header format. The modification time from the gzip header is
// used for the zip entry, unless it is not present, in which case the current
// local time is used for the zip entry. The file name from the gzip header is
// used for the zip entry, unless it is not present, in which case "-" is used.
// This does not use the Zip64 format, so the offsets in the resulting zip file
// must be less than 4GB. If name is not NULL, then the zero-terminated string
// at name is used as the file name for the single entry. Whether the file name
// comes from the gzip header or from name, it is truncated to 64K-1 characters
// if necessary.
//
// It is recommended that unzip -t be used on the resulting file to verify its
// integrity. If the gzip files do not obey the constraints above, then the zip
// file will not be valid.
local void gz2zip(FILE *in, FILE *out, char *name) {
// zip file constant headers for local, central, and end record
unsigned char const loc[] = {'P', 'K', 3, 4, 20, 0, 8, 0, 8, 0};
unsigned char const cen[] = {'P', 'K', 1, 2, 20, 0, 20, 0, 8, 0, 8, 0};
unsigned char const end[] = {'P', 'K', 5, 6, 0, 0, 0, 0, 1, 0, 1, 0};
// gzip header
unsigned char head[10];
// zip file modification date, CRC, and sizes -- initialize to zero for the
// local header (the actual CRC and sizes follow the compressed data)
unsigned char desc[16] = {0};
// name from gzip header to use for the zip entry (the maximum size of the
// name is 64K-1 -- if the gzip name is longer, then it is truncated)
unsigned name_len;
char save[65535];
// read and interpret the gzip header, bailing if it is invalid or has an
// unknown compression method or flag bits set
size_t got = fread(head, 1, sizeof(head), in);
if (got < sizeof(head) ||
head[0] != 0x1f || head[1] != 0x8b || head[2] != 8 || (head[3] & 0xe0))
bail("input not gzip");
if (head[3] & 4) { // extra field (ignore)
unsigned extra = getc(in);
int high = getc(in);
if (high == EOF)
bail("premature end of gzip input");
extra += (unsigned)high << 8;
fread(name, 1, extra, in);
}
if (head[3] & 8) { // file name (save)
name_len = 0;
int ch;
while ((ch = getc(in)) != 0 && ch != EOF)
if (name_len < sizeof(name))
save[name_len++] = ch;
}
else { // no file name
name_len = 1;
save[0] = '-';
}
if (head[3] & 16) { // comment (ignore)
int ch;
while ((ch = getc(in)) != 0 && ch != EOF)
;
}
if (head[3] & 2) { // header crc (ignore)
getc(in);
getc(in);
}
// use name from argument if present, otherwise from gzip header
if (name == NULL)
name = save;
else {
name_len = strlen(name);
if (name_len > 65535)
name_len = 65535;
}
// set modification time and date in descriptor from gzip header
time_t mod = head[4] + (head[5] << 8) + ((time_t)(head[6]) << 16) +
((time_t)(head[7]) << 24);
unix2dos(desc, mod ? mod : time(NULL));
// initialize tally of output bytes
tally_t zip = {out, 0};
// write zip local header
off_t locoff = zip.off;
put(&zip, loc, sizeof(loc));
put(&zip, desc, sizeof(desc));
put2(&zip, name_len);
putz(&zip, 2);
put(&zip, name, name_len);
// copy raw deflate stream, saving eight-byte gzip trailer
unsigned char buf[CHUNK + 8];
if (fread(buf, 1, 8, in) != 8)
bail("premature end of gzip input");
off_t comp = 0;
while ((got = fread(buf + 8, 1, CHUNK, in)) != 0) {
put(&zip, buf, got);
comp += got;
memmove(buf, buf + got, 8);
}
// write descriptor based on gzip trailer and compressed count
memcpy(desc + 4, buf, 4);
desc[8] = comp;
desc[9] = comp >> 8;
desc[10] = comp >> 16;
desc[11] = comp >> 24;
memcpy(desc + 12, buf + 4, 4);
put(&zip, desc + 4, sizeof(desc) - 4);
// write zip central directory
off_t cenoff = zip.off;
put(&zip, cen, sizeof(cen));
put(&zip, desc, sizeof(desc));
put2(&zip, name_len);
putz(&zip, 12);
put4(&zip, locoff);
put(&zip, name, name_len);
// write zip end-of-central-directory record
off_t endoff = zip.off;
put(&zip, end, sizeof(end));
put4(&zip, endoff - cenoff);
put4(&zip, cenoff);
putz(&zip, 2);
}
// Convert the gzip file on stdin to a zip file on stdout. If present, the
// first argument is used as the file name in the zip entry.
int main(int argc, char **argv) {
// avoid end-of-line conversions on evil operating systems
SET_BINARY_MODE(stdin);
SET_BINARY_MODE(stdout);
// convert .gz on stdin to .zip on stdout -- error returns use exit()
gz2zip(stdin, stdout, argc > 1 ? argv[1] : NULL);
return 0;
}
I have an issue – There is an application (P) which create an instance of the com component (F) which make calls from separate dll (U).
P(app)—CoCreateInstance()--->F(com .dll)-----(call)--->U(MFC extension.dll)------(call libcurl.dll)
I create small test console application
#include "stdafx.h"
#include <iostream>
#include "curl/curl.h"
static std::string readBuffer;
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
readBuffer.append((const char*)contents, realsize);
return realsize;
}
int blocking_curl()
{
const std::string endPointUrl = "https://somecoolserver.com/resource";
const std::string urlparam = "param1=pValue1¶m2=pValue2& param3=pValue3 ";
const std::string cookie = "";
const std::string httpHeadAccept = "application/xml";
const std::string httpContentType = "Content-Type: application/x-www-form-urlencoded";
const std::string AuthCertficate = "";
const std::string OAuthToken = "";
CURL *curl = NULL;
CURLcode res = CURLE_FAILED_INIT;
struct curl_slist *headers = NULL;
curl = curl_easy_init();
if(!curl)
{
return res;
}
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, endPointUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, urlparam.c_str());
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
headers = curl_slist_append(headers, httpHeadAccept.c_str());
headers = curl_slist_append(headers, httpContentType.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
headers = curl_slist_append(headers, OAuthToken.c_str());
readBuffer.clear();
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
if (!cookie.empty())
{
headers = curl_slist_append(headers, AuthCertficate.c_str());
std::string pCookie = "somestring=";
pCookie += cookie;
curl_easy_setopt(curl, CURLOPT_COOKIE, pCookie.c_str());
}
else
{
headers = curl_slist_append(headers, OAuthToken.c_str());
}
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
std::cout << "Response: " << readBuffer.c_str() << std::endl;
return res;
}
int _tmain(int argc, _TCHAR* argv[])
{
blocking_curl();
return 0;
}
This code works fine and I get in readBuffer the exact a such result as I expect.
However, if I directly copy this code to my U dll (more exactly replace such a code within called function) this code hangs on curl_easy_perform. Version of libcurl 7.54.0. I see in debugger all correct flow and call stack – but in U dll it hangs on curl_easy_perform. I even have no idea how it is possible! In debugger I see libcurl.dll is loaded and the version (7.54.0) is correct. All parameters are hardcoded (url, url parameters and so on) but in one case it works and for another doesn’t! Additionally I created another function with multi interface but it is also doesn’t work.
I have two ideas:
The com component load U dll and U dll try to load libcurl.dll somewhere from the system. My searching through the file system shows there is several version of libcurl.dll in the system. One for MacAfee antivirus and one in Microsoft office. However if I put the call curl_version() before curl_easy_perform I see as a result correct version. I can’t 100% be sure it is correct because this string may be get on compile time but actually it load libcurl of the other version.
Com component may have different address space and U dll actually can’t find the library. I also thing it is correct because all other calls are correct including curl_init..
But what else?! If somebody have any ideas please share.
The issue was a result of call the function of dll (U) with libcurl code in InitInstance method of dll F (COM component). After moving all libcurl routine to the other working methods everything have worked fine.
after downloading ZLIB ver. 1.2.11 and looking through RFC1951
I'm trying to use ZLIB.inflate function like this:
#include "zlib.h"
int iRslt;
unsigned char buffIn[4]={0x4b,4,0,0};
unsigned char buffOut[16];
z_stream zStrm;
memset(&zStrm, 0, sizeof(zStrm));
zStrm.zalloc = Z_NULL;
zStrm.zfree = Z_NULL;
zStrm.opaque = Z_NULL;
zStrm.avail_in = 0;
zStrm.next_in = Z_NULL;
iRslt = inflateInit(&zStrm);
if(iRslt != Z_OK) return;
zStrm.avail_in = sizeof(buffIn);
zStrm.next_in = buffIn;
zStrm.avail_out = sizeof(buffOut);
zStrm.next_out = buffOut;
iRslt = inflate(&zStrm, Z_NO_FLUSH);
if(iRslt == Z_DATA_ERROR){//-3
//why do I end up here with zStrm.msg -> "incorrect header check"?
}
My buffIn contains bitstream header 011b: BFINAL=1; BTYPE=01b; and fixed Huffman code for character 'a' (0x61) followed by at least 7 zero bits to end the block. Evidently that's not enough; please help.
Many thanks in advance;
Boba.
Your code is looking for a zlib stream header, as defined in RFC 1950. It's not finding it. That RFC defines the zlib header and trailer that is wrapped around a raw deflate stream.
You have a raw deflate stream in your question. To decode that instead of a zlib stream, you would need to use inflateInit2() with a windowBits value of -15.
I'm using G-WAN Web App. Server v7.12.6.
How to return valid Status Code: 200 OK if request URL has a total of 541+ characters including the 25 parameters?
ajaxGet(URL, method) where method is GET or PUT (same result)
Request URL:
http://myWebsite.ca:xx/?createCompany.c&legalname=mycomp&dba=mycomp%20dba&www=www.myWebsite...
createCompany.c
#pragma link "pq"
#include <stdlib.h>
#include <string.h>
#include "/usr/include/postgresql/libpq-fe.h"
#include "gwan.h"
//----------------------------------------------------------------------------
int main(int argc, char *argv[]) {
u64 start = getus();
PGconn *conn;
PGresult *res;
char DBrequestString [1000] = "";
char *legal_name = 0, *dba = 0, *www = 0; //...+ 22 more
xbuf_t *reply = get_reply(argv);
get_arg("legalname=", &legal_name, argc, argv);
get_arg("dba=", &dba, argc, argv);
get_arg("www=", &www, argc, argv);
//...+ 22 more
char requestString[1000] = "SELECT create_company('%s','%s','%s', ... + 22 more);";
sprintf(DBrequestString, requestString,legal_name, dba, www, ... + 22 more);
conn = PQconnectdb("host=x port=x dbname=x user=x password=x");
if (PQstatus(conn) != CONNECTION_OK){
fprintf(stderr, "Connection to database failed: %s",PQerrorMessage(conn));
PQfinish(conn);
xbuf_cat(reply, "{\"message\":\"Connection to database failed !\"}");//message Json format
return 200;
}
res = PQexec(conn, DBrequestString);
printf(" --> %s\n",PQgetvalue(res, 0, 0));
xbuf_cat(reply, PQgetvalue(res, 0, 0));//return one line Json format
PQclear(res);
PQfinish(conn);
printf("TEMPS D'EXECUTION: %.2Fms\n\n",(getus() - start)/1000.0);
return 200; //return OK
}
Good question - I don't have access to the source code righ tnow but looking at the G-WAN API on the website made me think that either READ_XBUF or MAX_ENTITY_SIZE might help.
Typically, READ_XBUF would be used in a G-WAN HANDLER to augment (if needed) the connection buffer while MAX_ENTITY_SIZE is a one-time setting that can be changed at any time (and even before the server starts, thanks to the init.c script).
I think that just enlarging the MAX_ENTITY_SIZE value (which purpose is to prevent lage-entity DoS attacks) would do the job because it is most likely that G-WAN automatically enlarges the READ_XBUF on a per request basis when reading from the client.
Thank you for your quick response.
I updated the script createCompany.c to raise the limit (as per your example):
u32 *old_entity_size = (u32*)get_env(argv, MAX_ENTITY_SIZE);
u32 new_entity_size = 2 * 1024 * 1024; // 2 MiB
*old_entity_size = new_entity_size; // raise the limit to 2 MiB
It's that possible the MAX_ENTITY_SIZE it's exclusively for POST request?
Raising the MAX_ENTITY_SIZE limit will work for GET/PUT requests also?
Actualy, I would like the limit to remain as initialy setup by default by G-WAN, useful for the other .c scripts,
but to raise the limit for GET/PUT requests only for this particular script createCompany.c
Any script.c example how to raise the limit for READ_XBUF?