Skip to content
Permalink
Browse files

Version 2.07 implements supports for keys with no = sign, which are a…

…ssigned an empty string as a value. Thanks to Geoff Mulligan for the suggestion. Also added some simple unit tests to cover this change and its possible side effects on other things.
  • Loading branch information...
boutell committed Feb 28, 2016
1 parent 437fa83 commit 7993c2143d805e37e519df92fa047765179bd8fb
Showing with 88 additions and 20 deletions.
  1. +5 −0 .gitignore
  2. +3 −0 Makefile
  3. +61 −6 cgic.c
  4. +16 −11 cgic.html
  5. +3 −3 support.txt
@@ -0,0 +1,5 @@
*.a
*.o
*.cgi
capture
cgicunittest
@@ -27,3 +27,6 @@ capture: capture.o libcgic.a
clean:
rm -f *.o *.a cgictest.cgi capture

test:
gcc -D UNIT_TEST=1 cgic.c -o cgicunittest
./cgicunittest
67 cgic.c
@@ -90,7 +90,7 @@ typedef enum {
VALUES. Make local copies if modifications are desired. */

typedef struct cgiFormEntryStruct {
char *attr;
char *attr;
/* value is populated for regular form fields only.
For file uploads, it points to an empty string, and file
upload data should be read from the file tfileName. */
@@ -100,7 +100,7 @@ typedef struct cgiFormEntryStruct {
/* Valid for both files and regular fields; does not include
terminating null of regular fields. */
int valueLength;
char *fileName;
char *fileName;
char *contentType;
/* Temporary file name for working storage of file uploads. */
char *tfileName;
@@ -119,6 +119,10 @@ static void cgiFreeResources();
static int cgiStrEqNc(char *s1, char *s2);
static int cgiStrBeginsNc(char *s1, char *s2);

#ifdef UNIT_TEST
static int unitTest();
#endif

int main(int argc, char *argv[]) {
int result;
char *cgiContentLengthString;
@@ -287,9 +291,14 @@ int main(int argc, char *argv[]) {
#endif /* CGICDEBUG */
}
}
result = cgiMain();
#ifdef UNIT_TEST
unitTest();
cgiFreeResources();
return 0;
#else
result = cgiMain();
return result;
#endif
}

static void cgiGetenv(char **s, char *var){
@@ -996,22 +1005,25 @@ static cgiParseResultType cgiParseFormInput(char *data, int length) {
cgiFormEntry *n;
cgiFormEntry *l = 0;
while (pos != length) {
int foundEq = 0;
int foundAmp = 0;
int start = pos;
int len = 0;
char *attr;
char *value;
while (pos != length) {
if (data[pos] == '&') {
/* Tolerate attr name without a value. This will fall through
and give us an empty value */
break;
}
if (data[pos] == '=') {
foundEq = 1;
pos++;
break;
}
pos++;
len++;
}
if (!foundEq) {
if (!len) {
break;
}
if (cgiUnescapeChars(&attr, data+start, len)
@@ -2538,3 +2550,46 @@ cgiFormResultType cgiValueEscape(const char *s)
}


#ifdef UNIT_TEST

static void unitTestAssert(const int value, const char *message);

static int unitTest() {
char *input = "one=1&two=2&empty1&four=4&empty2";
cgiFormEntry *e;
cgiParseResultType result = cgiParseFormInput(input, strlen(input));
unitTestAssert(result == cgiParseSuccess, "cgiParseFormInput did not return cgiParseSuccess");
e = cgiFormEntryFirst;
unitTestAssert(!!e, "first entry missing");
unitTestAssert(!strcmp(e->attr, "one"), "first entry name is not one");
unitTestAssert(!strcmp(e->value, "1"), "first entry value is not 1");
e = e->next;
unitTestAssert(!!e, "Test failed: second entry missing");
unitTestAssert(!strcmp(e->attr, "two"), "second entry name is not two");
unitTestAssert(!strcmp(e->value, "2"), "second entry value is not 2");
e = e->next;
unitTestAssert(!!e, "Test failed: third entry missing");
unitTestAssert(!strcmp(e->attr, "empty1"), "third entry name is not empty1");
unitTestAssert(!strcmp(e->value, ""), "third entry value is not empty string");
e = e->next;
unitTestAssert(!!e, "Test failed: fourth entry missing");
unitTestAssert(!strcmp(e->attr, "four"), "fourth entry name is not four");
unitTestAssert(!strcmp(e->value, "4"), "fourth entry value is not 4");
e = e->next;
unitTestAssert(!!e, "Test failed: fifth entry missing");
unitTestAssert(!strcmp(e->attr, "empty2"), "fifth entry name is not empty2");
unitTestAssert(!strcmp(e->value, ""), "fifth entry value is not empty string");
unitTestAssert(!e->next, "unexpected entry at end of list");
return 0;
}

static void unitTestAssert(const int value, const char *message)
{
if (value) {
return;
}
fprintf(stderr, "Test failed: %s\n", message);
exit(1);
}

#endif
@@ -3,7 +3,7 @@
<title>cgic: an ANSI C library for CGI Programming</title>
</head>
<body>
<h1>cgic 2.05: an ANSI C library for CGI Programming</h1>
<h1>cgic 2.07: an ANSI C library for CGI Programming</h1>
<h2>By <a href="http://www.boutell.com/boutell/">Thomas Boutell</a></h2>
<em><a href="http://www.boutell.com/cgic/">
The LATEST documentation is available here. Check often
@@ -80,6 +80,11 @@ <h4>Hourly Support</h4>
our <a href="https://www.boutell.com/freeform/">secure
message page</a>. To avoid delay, be sure to specifically mention
that you wish to purchase CGIC support at the hourly rate above.
<h3><a name="whatsnew207">What's new in version 2.07?</a></h3>
Per a suggestion by Geoff Mulligan, cgic now tolerates keys without a value in URL-encoded GET and POST submissions. Although the HTML5 spec discourages it, there are existing systems in the wild that do leave the `=` off entirely if the value is an empty string. Beginning with version 2.07, `cgic` handles this as you'd expect: you get an entry with the corresponding key and an empty string as the value. A simple unit test compilation target was also added, to test this feature and rule out side effects.
<h3><a name="whatsnew206">What's new in version 2.06?</a></h3>
A long list of significant fixes generously contributed by Jeffrey Hutzelman.
<a href="https://github.com/boutell/cgic/commit/2065a2dfa480209bd6171acb2a4edd6e1c27a062"> These are especially important on platforms where attempting to read beyong the content length stated by the request can lead to a deadlock. Please see the commit notes.</a>
<h3><a name="whatsnew205">What's new in version 2.05?</a></h3>
Uploaded files properly closed; corrects a resource leak and enables
file uploads to work properly on platforms with particular file
@@ -307,28 +312,28 @@ <h4>What Operating System Does Your WEB SERVER Run?</h4>
operating systems, save it, then issue the following
commands to unpack it:
<pre>
gunzip cgic205.tar.gz
tar -xf cgic205.tar
gunzip cgic207.tar.gz
tar -xf cgic207.tar
</pre>
This should produce the subdirectory 'cgic205', which will contain
the complete cgic distribution for version 2.05, including a copy of this
This should produce the subdirectory 'cgic207', which will contain
the complete cgic distribution for version 2.07, including a copy of this
documentation in the file cgic.html.
<p>
Under Windows and compatible operating systems, save it,
open a console ("DOS") window, and issue the following commands to unpack it:
open a command prompt window, and issue the following commands to unpack it:
<pre>
unzip /d cgic205.zip
unzip /d cgic207.zip
</pre>
Or use the unzip utility of your choice.
<p>
This command also produces the subdirectory 'cgic205', which will contain
the complete cgic distribution for version 2.0, including a copy of this
This command also produces the subdirectory 'cgic207', which will contain
the complete cgic distribution, including a copy of this
documentation in the file cgic.html.
<p>
cgic is available via the web from www.boutell.com:
<ul>
<li><a href="http://www.boutell.com/cgic/cgic205.tar.gz">Obtain cgic: gzipped tar file</a>
<li><a href="http://www.boutell.com/cgic/cgic205.zip">Obtain cgic: .ZIP file</a>
<li><a href="http://www.boutell.com/cgic/cgic207.tar.gz">Obtain cgic: gzipped tar file</a>
<li><a href="http://www.boutell.com/cgic/cgic207.zip">Obtain cgic: .ZIP file</a>
</ul>
<h3><a name="build">Building cgic: a sample application</a></h3>
The sample application 'cgictest.c' is provided as part of the
@@ -34,10 +34,10 @@ Those requiring support in detail may arrange for direct support
from the author, Thomas Boutell, at the rate of $50/hr, billed
directly by credit card. Purchase orders are also accepted from
Fortune 500 corporations and institutions in good standing.
To make arrangements, contact boutell@boutell.com. Alternatively,
use our free-form secure message page at:
To make arrangements, contact boutell@boutell.com or use this
secure form which permits attachments:

https://www.boutell.com/freeform/
https://www.boutell.com/securemail/

To avoid delay and/or confusion, be sure to specifically mention that
you wish to purchase CGIC support at the hourly rate above.

0 comments on commit 7993c21

Please sign in to comment.
You can’t perform that action at this time.