Thread overview
D CGI Hang with fgets
Nov 27, 2006
Morgan McDermott
Nov 27, 2006
Carlos Santander
Nov 27, 2006
Morgan McDermott
Nov 28, 2006
Morgan McDermott
Nov 28, 2006
Thomas Kuehne
November 27, 2006
Hi there!
 I'm trying to make a D CGI script, and one of the essential things it should do is to get POST data. My attempt below in D hangs at fgets()... I've made it output to a file so that it may be tested on a webserver (where I've been testing it). When the script has POST data to get, it performs exactly the same as it does in the console (hangs at fgets()).

I've been using a guide to C and CGI as my reference here:
http://www.cs.tut.fi/~jkorpela/forms/cgic.html

<code>
//Imports
import std.stdio; //writefln()
import std.string; //toString()
import std.date : getUTCtime; // time + benchmarking
import std.conv; //toInt()
import std.stream; //testing only
	
alias char[] string; //ease of use

void writeNewLine(string line, string filename) {
	std.file.append(filename, line~"\n");
}

extern (C)
	{
		char* getPOSTData(uint len = 2048){
			char *prawData;

			printf("hang?");
			writeNewLine("Hanging point entered \n", "baz.txt");

			prawData = fgets(prawData, len+1, stdin);

			writeNewLine("Hanging point exited \n", "baz.txt");
			printf("Not hanging.. =-)");

			return prawData;
		}
	}
	
extern (C) char* getenv(char*);

void main() {
	string introduction = "New test at " ~ toString(getUTCtime());
	writeNewLine(introduction, "baz.txt");
	
	char *pdataLength= getenv("CONTENT_LENGTH");
	string scontentLength = toString(pdataLength);
	//Ensure no conversion error when no post data is passed
		if(scontentLength == ""){
			scontentLength = "0";
		}
	
	uint contentLength = toInt(scontentLength);
	
	char *ppostData = getPOSTData();
	writefln("Post Data: %s", toString(ppostData));
	writeNewLine("Post Data: " ~ toString(ppostData), "baz.txt");
}
</code>

Any ideas?

Thank you very much for your time,
 ~Morgan McDermott
November 27, 2006
Morgan McDermott escribió:
> Hi there!
>  I'm trying to make a D CGI script, and one of the essential things it should do is to get POST data. My attempt below in D hangs at fgets()... I've made it output to a file so that it may be tested on a webserver (where I've been testing it). When the script has POST data to get, it performs exactly the same as it does in the console (hangs at fgets()).
> 
> I've been using a guide to C and CGI as my reference here:
> http://www.cs.tut.fi/~jkorpela/forms/cgic.html
> 
> <code>
> //Imports
> import std.stdio; //writefln()
> import std.string; //toString()
> import std.date : getUTCtime; // time + benchmarking
> import std.conv; //toInt()
> import std.stream; //testing only
>     alias char[] string; //ease of use
> 
> void writeNewLine(string line, string filename) {
>     std.file.append(filename, line~"\n");
> }
> 
> extern (C)
>     {
>         char* getPOSTData(uint len = 2048){
>             char *prawData;
> 

Have you tried initializing prawData?
prawData = new char [len];  // or similar

>             printf("hang?");
>             writeNewLine("Hanging point entered \n", "baz.txt");
> 
>             prawData = fgets(prawData, len+1, stdin);
> 
>             writeNewLine("Hanging point exited \n", "baz.txt");
>             printf("Not hanging.. =-)");
> 
>             return prawData;
>         }
>     }
>     extern (C) char* getenv(char*);
> 
> void main() {
>     string introduction = "New test at " ~ toString(getUTCtime());
>     writeNewLine(introduction, "baz.txt");
>         char *pdataLength= getenv("CONTENT_LENGTH");
>     string scontentLength = toString(pdataLength);
>     //Ensure no conversion error when no post data is passed
>         if(scontentLength == ""){
>             scontentLength = "0";
>         }
>         uint contentLength = toInt(scontentLength);
>         char *ppostData = getPOSTData();
>     writefln("Post Data: %s", toString(ppostData));
>     writeNewLine("Post Data: " ~ toString(ppostData), "baz.txt");
> }
> </code>
> 
> Any ideas?
> 
> Thank you very much for your time,
>  ~Morgan McDermott


-- 
Carlos Santander Bernal
November 27, 2006
Carlos Santander wrote:
> Morgan McDermott escribió:
>> Hi there!
>>  I'm trying to make a D CGI script, and one of the essential things it should do is to get POST data. My attempt below in D hangs at fgets()... I've made it output to a file so that it may be tested on a webserver (where I've been testing it). When the script has POST data to get, it performs exactly the same as it does in the console (hangs at fgets()).
>>
>> I've been using a guide to C and CGI as my reference here:
>> http://www.cs.tut.fi/~jkorpela/forms/cgic.html
>>
>> <code>
>> //Imports
>> import std.stdio; //writefln()
>> import std.string; //toString()
>> import std.date : getUTCtime; // time + benchmarking
>> import std.conv; //toInt()
>> import std.stream; //testing only
>>     alias char[] string; //ease of use
>>
>> void writeNewLine(string line, string filename) {
>>     std.file.append(filename, line~"\n");
>> }
>>
>> extern (C)
>>     {
>>         char* getPOSTData(uint len = 2048){
>>             char *prawData;
>>
> 
> Have you tried initializing prawData?
> prawData = new char [len];  // or similar
> 
>>             printf("hang?");
>>             writeNewLine("Hanging point entered \n", "baz.txt");
>>
>>             prawData = fgets(prawData, len+1, stdin);
>>
>>             writeNewLine("Hanging point exited \n", "baz.txt");
>>             printf("Not hanging.. =-)");
>>
>>             return prawData;
>>         }
>>     }
>>     extern (C) char* getenv(char*);
>>
>> void main() {
>>     string introduction = "New test at " ~ toString(getUTCtime());
>>     writeNewLine(introduction, "baz.txt");
>>         char *pdataLength= getenv("CONTENT_LENGTH");
>>     string scontentLength = toString(pdataLength);
>>     //Ensure no conversion error when no post data is passed
>>         if(scontentLength == ""){
>>             scontentLength = "0";
>>         }
>>         uint contentLength = toInt(scontentLength);
>>         char *ppostData = getPOSTData();
>>     writefln("Post Data: %s", toString(ppostData));
>>     writeNewLine("Post Data: " ~ toString(ppostData), "baz.txt");
>> }
>> </code>
>>
>> Any ideas?
>>
>> Thank you very much for your time,
>>  ~Morgan McDermott
> 
> 
Carlos,
 Good idea, and thanks for the reply. Unfortunately, the script still hangs at the same point. I've done a bit more work and an essentially equivilant C script also hangs at this point, so I doubt that this is a D-problem. All the same, any help from this great community is very much appreciated :).

 Thanks again,
  ~Morgan McDermott
November 28, 2006
Morgan McDermott schrieb am 2006-11-27:
> Hi there!
>   I'm trying to make a D CGI script, and one of the essential things it
> should do is to get POST data. My attempt below in D hangs at fgets()...
> I've made it output to a file so that it may be tested on a webserver
> (where I've been testing it). When the script has POST data to get, it
> performs exactly the same as it does in the console (hangs at fgets()).
>
> I've been using a guide to C and CGI as my reference here: http://www.cs.tut.fi/~jkorpela/forms/cgic.html
>
><code>
> //Imports
> import std.stdio; //writefln()
> import std.string; //toString()
> import std.date : getUTCtime; // time + benchmarking
> import std.conv; //toInt()
> import std.stream; //testing only
> 
> alias char[] string; //ease of use
>
> void writeNewLine(string line, string filename) {
> 	std.file.append(filename, line~"\n");
> }
>
> extern (C)
> 	{
> 		char* getPOSTData(uint len = 2048){
> 			char *prawData;
>
> 			printf("hang?");
> 			writeNewLine("Hanging point entered \n", "baz.txt");
>
> 			prawData = fgets(prawData, len+1, stdin);
>
> 			writeNewLine("Hanging point exited \n", "baz.txt");
> 			printf("Not hanging.. =-)");
>
> 			return prawData;
> 		}
> 	}
> 
> extern (C) char* getenv(char*);
>
> void main() {
> 	string introduction = "New test at " ~ toString(getUTCtime());
> 	writeNewLine(introduction, "baz.txt");
> 
> 	char *pdataLength= getenv("CONTENT_LENGTH");
> 	string scontentLength = toString(pdataLength);
> 	//Ensure no conversion error when no post data is passed
> 		if(scontentLength == ""){
> 			scontentLength = "0";
> 		}
> 
> 	uint contentLength = toInt(scontentLength);
> 
> 	char *ppostData = getPOSTData();
> 	writefln("Post Data: %s", toString(ppostData));
> 	writeNewLine("Post Data: " ~ toString(ppostData), "baz.txt");
> }
></code>
>
> Any ideas?

Change

# char *prawData;

to

# char *prawData = (new char[len]).ptr;

And send intput to stdin e.g.:
#
# programm < some_file
#

Thomas


November 28, 2006
Morgan McDermott wrote:
> Carlos Santander wrote:
>> Morgan McDermott escribió:
>>> Hi there!
>>>  I'm trying to make a D CGI script, and one of the essential things it should do is to get POST data. My attempt below in D hangs at fgets()... I've made it output to a file so that it may be tested on a webserver (where I've been testing it). When the script has POST data to get, it performs exactly the same as it does in the console (hangs at fgets()).
>>>
>>> I've been using a guide to C and CGI as my reference here:
>>> http://www.cs.tut.fi/~jkorpela/forms/cgic.html
>>>
>>> <code>
>>> //Imports
>>> import std.stdio; //writefln()
>>> import std.string; //toString()
>>> import std.date : getUTCtime; // time + benchmarking
>>> import std.conv; //toInt()
>>> import std.stream; //testing only
>>>     alias char[] string; //ease of use
>>>
>>> void writeNewLine(string line, string filename) {
>>>     std.file.append(filename, line~"\n");
>>> }
>>>
>>> extern (C)
>>>     {
>>>         char* getPOSTData(uint len = 2048){
>>>             char *prawData;
>>>
>>
>> Have you tried initializing prawData?
>> prawData = new char [len];  // or similar
>>
>>>             printf("hang?");
>>>             writeNewLine("Hanging point entered \n", "baz.txt");
>>>
>>>             prawData = fgets(prawData, len+1, stdin);
>>>
>>>             writeNewLine("Hanging point exited \n", "baz.txt");
>>>             printf("Not hanging.. =-)");
>>>
>>>             return prawData;
>>>         }
>>>     }
>>>     extern (C) char* getenv(char*);
>>>
>>> void main() {
>>>     string introduction = "New test at " ~ toString(getUTCtime());
>>>     writeNewLine(introduction, "baz.txt");
>>>         char *pdataLength= getenv("CONTENT_LENGTH");
>>>     string scontentLength = toString(pdataLength);
>>>     //Ensure no conversion error when no post data is passed
>>>         if(scontentLength == ""){
>>>             scontentLength = "0";
>>>         }
>>>         uint contentLength = toInt(scontentLength);
>>>         char *ppostData = getPOSTData();
>>>     writefln("Post Data: %s", toString(ppostData));
>>>     writeNewLine("Post Data: " ~ toString(ppostData), "baz.txt");
>>> }
>>> </code>
>>>
>>> Any ideas?
>>>
>>> Thank you very much for your time,
>>>  ~Morgan McDermott
>>
>>
> Carlos,
>  Good idea, and thanks for the reply. Unfortunately, the script still hangs at the same point. I've done a bit more work and an essentially equivilant C script also hangs at this point, so I doubt that this is a D-problem. All the same, any help from this great community is very much appreciated :).
> 
>  Thanks again,
>   ~Morgan McDermott

Further research leads me to conclude that the problem is giving fgets a pointer instead of a char array. When I replace prawData with something like rawData[1000], everything works as planned.
<code>
char rawData[1000];
fgets(rawData, len+1, stdin);
</code>
Although this works, I would really rather put the data from stdin into something of variable size. I got my C-code to work with this modification, so I ported it over to D and allowed it to take as much data as you want it to by looping through the stdin data. I haven't optimized buffer size for anything in particular... If you plan on using this function, then you probably want to play around with that.

To use this in a CGI environment, you're going to need to:
 1) split apart the data into key value pairs
 2) decode the data with an unencode function ( Cashew has one )

<code>
//Imports
	import std.stdio; //writefln
	import std.string;
	
	import std.c.stdlib; //Environmental Vars
	import std.c.stdio; //fgets
	import std.c.string;
	
	alias char[] string;
	
	extern (C) char* getenv(char*);

	char[] d_getPOSTData(uint maxlen = 2048){
				//Buffer info
				char dataBuffer[512];
				ulong bufferSize = dataBuffer.length;
				
				//Define some pointers
				char *lenstr;
				char *pblank;
				char[] error;
				
				//Variable to hold lenstr in int form
				long len;
				
				lenstr = getenv("CONTENT_LENGTH");
				//Test for null length
				if(lenstr == pblank){
					//throw error
					error = "No POST data";
					return error;
				}
				else {
					//copy lenstr into len with format width=long, type = decimal integer
					sscanf(lenstr,"%ld",&len);
				}
				if( len > maxlen ){
					error = "POST data has exceeded size limits";
					return error;
				}
				else {
					char *ptmpData;
					char[] tempString;
					char[] dataStorage;
					
					//While stream pointer is at a valid location, [stdin has more data to give us]
					while(fgets(dataBuffer, bufferSize, stdin)){
						//Set pointer to buffer
						ptmpData = dataBuffer;			
						
						//Get the contents of the buffer into tempString
						tempString = toString(ptmpData);
						
						//Append tempString to dataStorage
						dataStorage ~= tempString;
					}	
					if(dataStorage.length >= len){
						dataStorage.length = len - 1;
					}
					return dataStorage;
				  }
			}
	
void main(){
	//Output HTTP headers -- Necessary when testing on Apache
		string ctype = "Content-Type:text/html;charset=";
		string encoding = "iso-8859-1";
		string char1 = "\x0D";
		string char2 = "\x0A";
		writef("%s%s%s%s\n", ctype, encoding,char1,char2);
		
	char[] postData = d_getPOSTData();
	writefln("Post Data: %s", postData);
}
</code>

**Problem solved**

Thank you for your help, D Community ^_~.