D CGI Hang with fgets

Morgan McDermott morganmcdermott at gmail.com
Mon Nov 27 22:35:50 PST 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 ^_~.



More information about the Digitalmars-d-learn mailing list