int urldecode(char *src, char *last, char *dest)

G

gert

This based on a example i found at http://www.cs.tut.fi/~jkorpela/
forms/cgic.html

#include <fcgi_stdio.h>
#include <stdlib.h>

int urldecode(char *src, char *last, char *dest){
int code;
for (; src != last; src++, dest++){
if (*src == '+') *dest = ' ';
else if(*src == '%') {
if(sscanf(src+1, "%2x", &code) != 1) code = '?';
*dest = code;
src +=2;
}
else *dest = *src;
}
*dest = '\n';
*++dest = '\0';
return 0;
}

int post(char *output){
char *lenstr=getenv("CONTENT_LENGTH");
char *input;
long len;
if (lenstr != NULL && sscanf(lenstr, "%ld", &len) == 1) {
fgets(input, len+1, stdin);
urldecode(input, input+len, output);
}
return 0;
}

int main (void){
char *output;
while (FCGI_Accept() >= 0) {
post(output);
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"%s"
"\n"
,output);
}
return 0;
}

The only thing i did is simplified it a bit so i could understand it a
bit better. The goal is to read the post from a xmlhttprequest and
return its contents back.

So far i receive the post but the urldecoding seems not to play along
and scrambles the output, any suggestions ?
 
G

gert

This based on a example i found athttp://www.cs.tut.fi/~jkorpela/
forms/cgic.html

#include <fcgi_stdio.h>
#include <stdlib.h>

int urldecode(char *src, char *last, char *dest){
int code;
for (; src != last; src++, dest++){
if (*src == '+') *dest = ' ';
else if(*src == '%') {
if(sscanf(src+1, "%2x", &code) != 1) code = '?';
*dest = code;
src +=2;
}
else *dest = *src;
}
*dest = '\n';
*++dest = '\0';
return 0;

}

int post(char *output){
char *lenstr=getenv("CONTENT_LENGTH");
char *input;
long len;
if (lenstr != NULL && sscanf(lenstr, "%ld", &len) == 1) {
fgets(input, len+1, stdin);
urldecode(input, input+len, output);
}
return 0;

}

int main (void){
char *output;
while (FCGI_Accept() >= 0) {
post(output);
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"%s"
"\n"
,output);
}
return 0;

}

The only thing i did is simplified it a bit so i could understand it a
bit better. The goal is to read the post from a xmlhttprequest and
return its contents back.

So far i receive the post but the urldecoding seems not to play along
and scrambles the output, any suggestions ?

better do it like this i think :)

if (lenstr != NULL ) {
sscanf(lenstr, "%ld", &len)
fgets(input, len+1, stdin);
urldecode(input, input+len, output);
}

still scrambely doh ?
 
I

Ian Collins

gert said:
This based on a example i found at http://www.cs.tut.fi/~jkorpela/
forms/cgic.html
The only thing i did is simplified it a bit so i could understand it a
bit better. The goal is to read the post from a xmlhttprequest and
return its contents back.

So far i receive the post but the urldecoding seems not to play along
and scrambles the output, any suggestions ?
Write some tests in order to understand how the code works.
 
C

Christopher Layne

gert said:
This based on a example i found at http://www.cs.tut.fi/~jkorpela/
forms/cgic.html

#include <fcgi_stdio.h>
#include <stdlib.h>

int urldecode(char *src, char *last, char *dest){
int code;
for (; src != last; src++, dest++){
if (*src == '+') *dest = ' ';
else if(*src == '%') {
if(sscanf(src+1, "%2x", &code) != 1) code = '?';
*dest = code;
src +=2;
}
else *dest = *src;
}
*dest = '\n';
*++dest = '\0';
return 0;
}

I had written something similar for a toy cgi form util I did a while back...
It's not super well checked for errors, but I do remember it atleast working.

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct cgi_var__ {
char *key;
char *val;
size_t key_l;
size_t val_l;
};

static int form_decode(cgi_var *cv, size_t off)
{
char c, tmp[4];
int r;

if (cv->val[off] != '%') {
fprintf(stdout, "form_decode: bad value\n");
return -1;
}

if ((r = (cv->val + cv->val_l) - (cv->val + off)) < 3) {
fprintf(stdout, "form_decode: length too short\n");
return -1;
}

memcpy(tmp, cv->val + off, MIN(3, r)); tmp[3] = '\0';
c = (unsigned char)strtol(tmp + 1, NULL, 16);

/*
* data == text%7Cj%25%5C%25
* 01234567890123456
*
* c == |, off == 4, r == 13
* c == %, off == 6, r == 9
* c == \, off == 7, r == 6
* c == %, off == 8, r == 3
*/

memcpy(cv->val + off, &c, sizeof c);
memmove(cv->val + off + 1, cv->val + off + 3, r - 3);

cv->val_l -= 2;
r = (cv->val + cv->val_l) - (cv->val + off);

return 0;
}

static int cv_filter(cgi_var *cv)
{
size_t i;

/* filter out rug-rats or decode %xx */
for (i = 0; i < cv->val_l; i++) {
if (cv->val == '%')
form_decode(cv, i);
switch (cv->val) {
case '+': case '\'': case '`': case '"':
cv->val = ' '; break;
default: break;
}
}

return 0;
}
 
G

gert

This based on a example i found athttp://www.cs.tut.fi/~jkorpela/
forms/cgic.html

#include <fcgi_stdio.h>
#include <stdlib.h>

int urldecode(char *src, char *last, char *dest){
int code;
for (; src != last; src++, dest++){
if (*src == '+') *dest = ' ';
else if(*src == '%') {
if(sscanf(src+1, "%2x", &code) != 1) code = '?';
*dest = code;
src +=2;
}
else *dest = *src;
}
*dest = '\n';
*++dest = '\0';
return 0;

}

int post(char *output){
char *lenstr=getenv("CONTENT_LENGTH");
char *input;
long len;
if (lenstr != NULL && sscanf(lenstr, "%ld", &len) == 1) {
fgets(input, len+1, stdin);
urldecode(input, input+len, output);
}
return 0;

}

int main (void){
char *output;
while (FCGI_Accept() >= 0) {
post(output);
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"%s"
"\n"
,output);
}
return 0;

}

My test tool doesnt work :( segmant fault, something to do with
stdin ???

#! /bin/sh
gcc -I /usr/local/include/ -L /usr/local/lib/ -l fcgi -o /home/gert/
Desktop/svn/db/bin/c /home/gert/Desktop/svn/db/bin/c.c
env CONTENT_LENGTH=3 /home/gert/Desktop/svn/db/bin/c << "test"
 
C

Christopher Layne

Uhh, fgets() needs a valid buffer to be writing into. You're just giving it a
pointer to an undefined location. Nothing has been allocated for it. There
are more basic things that need to be solved before you can approach even
getting your code to do what it is you want it to do.
 
G

gert

Uhh, fgets() needs a valid buffer to be writing into. You're just giving it a
pointer to an undefined location. Nothing has been allocated for it. There
are more basic things that need to be solved before you can approach even
getting your code to do what it is you want it to do.

And there goes my plans for the weekend :)
Better start with valid buffer then, this part came straight from the
example at http://www.cs.tut.fi/~jkorpela/forms/cgic.html

fgets(input, len+1, stdin);

Any other full cgi post examples please ?
 
F

Flash Gordon

gert wrote, On 14/02/07 19:40:
And there goes my plans for the weekend :)
Better start with valid buffer then, this part came straight from the
example at http://www.cs.tut.fi/~jkorpela/forms/cgic.html

fgets(input, len+1, stdin);

That specific line does, but the definition of input is different. You
have defined it as a pointer to char, the code at that URL defines it as
a char array.
Any other full cgi post examples please ?

I don't, but I suggest you start looking at the comp.lang.c FAQ (Google
will find it) and buy a copy of K&R2 (the full details are in the
bibliography of the FAQ). Then you can start learning C properly since
you need to know the language in order to write CGIs in it.
 
G

gert

#include <fcgi_stdio.h>
#include <stdlib.h>

int urldecode(char *src, char *last, char *dest){
int code;
for (; src != last; src++, dest++){
if (*src == '+') *dest = ' ';
else if(*src == '%') {
if(sscanf(src+1, "%2x", &code) != 1) code = '?';
*dest = code;
src +=2;
}
else *dest = *src;
}
*dest = '\n';
*++dest = '\0';
return 0;
}

int post(void){
char input[100];
char *lenstr;
long len;
lenstr=getenv("CONTENT_LENGTH");
if (lenstr != NULL && sscanf(lenstr,"%ld",&len)==1 ) {
fgets(input, len+1, stdin);
//urldecode(input, input+len, input);
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"<xml>%s %d</xml>"
"\n"
,input,len);
}
return 0;
}

int main (void){
char * input;
while (FCGI_Accept() >= 0) {
post();
}
return 0;
}

So far this works thx to flash gorden pointing out the char pointer

Can somebody explain why char * instead of [] only let me post 11
characters ? 12 characters equals segfault ?

my tool still displays hebrew doh but at least it doesnt give me a
segfault ?

#! /bin/sh
gcc -I /usr/local/include/ -L /usr/local/lib/ -l fcgi -o /home/gert/
Desktop/svn/db/bin/c /home/gert/Desktop/svn/db/bin/c.c
sudo /etc/init.d/lighttpd restart
env CONTENT_LENGTH=3 /home/gert/Desktop/svn/db/bin/c << "test" << EOF

gert@gert:~$ Desktop/svn/db/bin/make.sh
* Stopping web server
lighttpd [ ok ]
* Starting web server
lighttpd [ ok ]
Content-Type: text/xml; charset=utf-8

<xml>x+5?++ 3</xml>
gert@gert:~$
 
G

gert

#include <fcgi_stdio.h>
#include <stdlib.h>

int urldecode(char *src, char *last, char *dest){
int code;
for (; src != last; src++, dest++){
if (*src == '+') *dest = ' ';
else if(*src == '%') {
if(sscanf(src+1, "%2x", &code) != 1) code = '?';
*dest = code;
src +=2;
}
else *dest = *src;
}
*dest = '\n';
*++dest = '\0';
return 0;

}

int post(void){
char input[100];
char *lenstr;
long len;
lenstr=getenv("CONTENT_LENGTH");
if (lenstr != NULL && sscanf(lenstr,"%ld",&len)==1 ) {
fgets(input, len+1, stdin);
//urldecode(input, input+len, input);
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"<xml>%s %d</xml>"
"\n"
,input,len);
}
return 0;

}

int main (void){
char * input;
while (FCGI_Accept() >= 0) {
post();
}
return 0;

}

So far this works thx to flash gorden pointing out the char pointer

Can somebody explain why char * instead of [] only let me post 11
characters ? 12 characters equals segfault ?

Never mind i think i know why after reading Christopher Layne and
Flash Gordon answers a few times.

fgets just need some memory, not a pointer. PS can i make the []
dynamic with the sizeof the post without using maloc ?
my tool still displays hebrew doh but at least it doesnt give me a
segfault ?

#! /bin/sh
gcc -I /usr/local/include/ -L /usr/local/lib/ -l fcgi -o /home/gert/
Desktop/svn/db/bin/c /home/gert/Desktop/svn/db/bin/c.c
sudo /etc/init.d/lighttpd restart
env CONTENT_LENGTH=3 /home/gert/Desktop/svn/db/bin/c << "test" << EOF

gert@gert:~$ Desktop/svn/db/bin/make.sh
* Stopping web server
lighttpd [ ok ]
* Starting web server
lighttpd [ ok ]
Content-Type: text/xml; charset=utf-8

<xml>x+5?++ 3</xml>
gert@gert:~$

Still want to know about my tool that speak some foreign language "x+5?
++ 3" what ever that means or sound like :)

If you people dont mind telling me or point something out ?
 
G

gert

Still want to know about my tool that speak some foreign language "x+5?
++ 3" what ever that means or sound like :)

If you people dont mind telling me or point something out ?

Aha this works

#! /bin/sh
gcc -I /usr/local/include/ -L /usr/local/lib/ -l fcgi -o /home/gert/
Desktop/svn/db/bin/c /home/gert/Desktop/svn/db/bin/c.c
sudo /etc/init.d/lighttpd restart
env CONTENT_LENGTH=3 /home/gert/Desktop/svn/db/bin/c < /home/gert/
Desktop/svn/db/bin/test.txt

So that brings us to the folowing, what does << "some random text" <<
EOF actualy sent to the stdin ?

I am thinking a char pointer instead of a file pointer, then again i
thought a file pointer was the same as a char pointer :)
 
O

Old Wolf

int post(char *output){
char *lenstr=getenv("CONTENT_LENGTH");
char *input;
long len;
if (lenstr != NULL && sscanf(lenstr, "%ld", &len) == 1) {
fgets(input, len+1, stdin);
urldecode(input, input+len, output);
}
return 0;

}

int main (void){
char *output;
while (FCGI_Accept() >= 0) {
post(output);

You've neither allocated space for 'input', nor 'output'.

This is a dreadful piece of design, since it is very difficult
to know how much space to allocate for 'output'.

Furthermore, the "urldecode" function could run forever, because
of the "src += 2" bit. For example if the content is "%".

You should be able to find an example of a function like this
that is written by someone with a clue, it is a fairly common task.
 
O

Old Wolf

This based on a example i found athttp://www.cs.tut.fi/~jkorpela/
forms/cgic.html

I looked at this code, it is dreadful and I advise you to not take
it as gospel. As well as causing a buffer overflow if the text
ends in "%" or "%x", it causes a buffer overflow if the text is
shorter than 5 characters. Also it contains this gem:
printf("%s%c%c\n", "STUFF",13,10);

This is entirely equivalent to:
printf("%s\r\n\n", "STUFF");

(unless the compiling machine is not ASCII, in which case, it's
hard to foresee how the target will handle the \n anyway).

Amusingly, the author wrote:
"CGI programming in C is clumsy and error-prone."

It certainly is, if he is the one doing the writing!
 
G

gert

I looked at this code, it is dreadful and I advise you to not take
it as gospel. As well as causing a buffer overflow if the text
ends in "%" or "%x", it causes a buffer overflow if the text is
shorter than 5 characters. Also it contains this gem:
printf("%s%c%c\n", "STUFF",13,10);

This is entirely equivalent to:
printf("%s\r\n\n", "STUFF");

(unless the compiling machine is not ASCII, in which case, it's
hard to foresee how the target will handle the \n anyway).

Amusingly, the author wrote:

"CGI programming in C is clumsy and error-prone."

It certainly is, if he is the one doing the writing!


Made some changes to it :)

#include <fcgi_stdio.h>
#include <stdlib.h>

char *post(void){
char *input;
char *lenstr;
long len;
lenstr=getenv("CONTENT_LENGTH");
if (lenstr != NULL && sscanf(lenstr,"%ld",&len)==1 ) {
input = malloc(len+1);
fgets(input, len+1, stdin);
//urldecode(); IMPLEMENT LATER NEED SLEEP FIRST
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"<xml>%s %d</xml>"
"\n"
,input,len);
free(input);
}
return 0;
}

int main (void){
char * input;
while (FCGI_Accept() >= 0) {
post();
}
return 0;
}

Is this Wolf approved, meaning safety code with no memory leaks or
other memory violations ?
 
C

Chris Torek

Aha this works

#! /bin/sh
gcc -I /usr/local/include/ -L /usr/local/lib/ -l fcgi -o /home/gert/
Desktop/svn/db/bin/c /home/gert/Desktop/svn/db/bin/c.c
sudo /etc/init.d/lighttpd restart
env CONTENT_LENGTH=3 /home/gert/Desktop/svn/db/bin/c < /home/gert/
Desktop/svn/db/bin/test.txt

None of this has to to with C, though (well, gcc has a *little* to
do with C, if you specifically ask it to compile C code :) ).
So that brings us to the folowing, what does << "some random text" <<
EOF actualy sent to the stdin ?

You want comp.unix.programmer, where you can talk about how shells
implement "here documents".
 
O

Old Wolf

#include <fcgi_stdio.h>
#include <stdlib.h>

char *post(void){
char *input;
char *lenstr;
long len;
lenstr=getenv("CONTENT_LENGTH");
if (lenstr != NULL && sscanf(lenstr,"%ld",&len)==1 ) {
input = malloc(len+1);
fgets(input, len+1, stdin);
//urldecode(); IMPLEMENT LATER NEED SLEEP FIRST
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"<xml>%s %d</xml>"
"\n"
,input,len);
free(input);
}
return 0;

}

int main (void){
char * input;
while (FCGI_Accept() >= 0) {
post();
}
return 0;

}

Is this Wolf approved, meaning safety code with no memory leaks or
other memory violations ?

Not quite; you use %d to print a long, and you don't
check the result of malloc() for failure.

I can't comment on the non-standard things (ie. whether
or not the output is actually valid, and the behaviour
of the getenv() function), so I'll assume you know what
you're doing there.
 
G

gert

Not quite; you use %d to print a long, and you don't
check the result of malloc() for failure.

I can't comment on the non-standard things (ie. whether
or not the output is actually valid, and the behaviour
of the getenv() function), so I'll assume you know what
you're doing there.

Well i dont know anything about c yet but i think i get the hang off
understanding what old wolf is trying to explain to me :)

#include <fcgi_stdio.h>
#include <stdlib.h>

char *urldecode(char *src, char *last, char *dest){
int code;
for (; src != last; src++, dest++){
if (*src == '+') *dest = ' ';
else if(*src == '%') {
if(sscanf(src+1, "%2x", &code) != 1) code = '?';
*dest = code;
src +=2;
}
else *dest = *src;
}
*dest = '\n';
*++dest = '\0';
return dest;
}

char *post(void){
char *input;
char *lenstr;
long len;
lenstr=getenv("CONTENT_LENGTH");
if (lenstr != NULL && sscanf(lenstr,"%ld",&len)==1 ) {
input = malloc(len+1);
if (input != NULL) {
fgets(input, len+1, stdin);
//urldecode(input, input+len, input);
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"<xml>%s</xml>"
"\n"
,input);
free(input);
}
}
return 0;
}

int main (void){
while (FCGI_Accept() >= 0) {
post();
}
return 0;
}

So i think this would cover the malloc check. The len that needed to
be %ld was only for seeing what was going on. Also char pointer in
main was obsolete.

Come to think about it not checking the malloc is more in the terms of
disaster waiting to happen if free() comes into play when malloc
failed, taking down ever www process including webserver , if i am not
mistaken ?
 
G

gert

#include <fcgi_stdio.h>
#include <stdlib.h>

char *post(void){
char *input;
char *lenstr;
long len;
lenstr=getenv("CONTENT_LENGTH");
if (lenstr != NULL && sscanf(lenstr,"%ld",&len)==1 ) {
input = malloc(len+1);
if (input != NULL) {
fgets(input, len+1, stdin);
printf("Content-Type: text/xml; charset=utf-8"
"\r\n"
"\r\n"
"<xml>%s</xml>"
"\n"
,input);
free(input);
}
}
return 0;
}

int main (void){
while (FCGI_Accept() >= 0) {
post();
}
return 0;
}

PS Do i actual need a urldecode function in the first place when using
post methode :) Isnt it supposed to be for decoding urls lol. My post
seems to be fine without decoding.
 
C

CBFalconer

Old said:
.... snip ...

I can't comment on the non-standard things (ie. whether
or not the output is actually valid, and the behaviour
of the getenv() function), so I'll assume you know what
you're doing there.
From N869:

7.20.4.5 The getenv function

Synopsis

[#1]
#include <stdlib.h>
char *getenv(const char *name);

Description

[#2] The getenv function searches an environment list,
provided by the host environment, for a string that matches
the string pointed to by name. The set of environment names
and the method for altering the environment list are
implementation-defined.

[#3] The implementation shall behave as if no library
function calls the getenv function.

Returns

[#4] The getenv function returns a pointer to a string
associated with the matched list member. The string pointed
to shall not be modified by the program, but may be
overwritten by a subsequent call to the getenv function. If
the specified name cannot be found, a null pointer is
returned.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
 
O

Old Wolf

char *post(void){
char *input;
char *lenstr;
long len;
lenstr=getenv("CONTENT_LENGTH");
if (lenstr != NULL && sscanf(lenstr,"%ld",&len)==1 ) {
input = malloc(len+1);
if (input != NULL) {
fgets(input, len+1, stdin);
//urldecode(input, input+len, input);

If you ever un-comment this, you will need to increase the
size of mallocked memory. This is because if the text
needs no conversion then it will have two extra characters
written on the end of it (a newline and a null character).
Come to think about it not checking the malloc is more in the terms of
disaster waiting to happen if free() comes into play when malloc
failed, taking down ever www process including webserver , if i am not
mistaken ?

free() is defined to do nothing, if you pass a null
pointer to it. The problem is because when you go
and write data to this null pointer, anything could
happen.

Whether or not you need the urldecode function, I can't
answer; you could see if there is a newsgroup for
CGI programming.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,169
Latest member
ArturoOlne
Top