#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    9
    Rep Power
    0

    Cgi upload file in C


    Hello!

    Problem with cgi upload file in C. When try to upload text file with "HelloWorld" content by form:
    <!DOCTYPE html>
    <html>
    <head>
    <script type="text/javascript">
    </script>
    </head>
    <body>
    <form ENCTYPE="multipart/form-data" method="POST" action="http://localhost/homecgi/cgi.exe">

    <INPUT NAME="fileupload" TYPE="file" /> <BR>
    <input type="submit" name="action" value="Submit" />

    </form>
    </body>
    </html>
    cgi script in C:

    int main(int argc, char *argv[]){

    char *method;
    int content_length;
    char * s_content;

    printf("%s%c%c\n", "Content-Type:text/html;charset=iso-8859-1",13,10);

    printf(" <html><title>Hello</title><body> \n");
    printf(" <BR><BR><strong> Uploading </strong>\n") ;
    method = getenv("REQUEST_METHOD");
    printf(" <BR><strong> Method: %s </strong>", method);

    content_length = atoi(getenv("CONTENT_LENGTH"));
    if(content_length == 0)
    return 0;

    printf("<BR><strong>content_length: %s %d </strong>", getenv("CONTENT_LENGTH"), content_length);

    s_content = (char *) malloc(sizeof(char) * content_length);
    if(s_content == NULL)
    return 0;

    fread(s_content, content_length, 1, stdin);

    printf("<p> s_content: %s </p>", s_content);

    printf(" </body></html>");
    return 1;
    }
    When submit is pressed, it is continous uploading:
    CGI Timeout
    The specified CGI application exceeded the allowed time for processing. The server has deleted the process.

    Why file isnt uploading?
  2. #2
  3. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    9
    Rep Power
    0
    Anyone help?

    These lines is where it could make problems:
    while(i < content_length ){
    fread(s_content, 1, 1, stdin);
    Seems that when in reading from stdin as stream, than there is no EOF, so it is reading continuously.

    But when size is fixed(although content_length should be fixed) then it works and file is uploaded till content_length - 30.
    For example:
    while(i < content_length - 30){
    fread(s_content, 1, 1, stdin);
    Why isnt enough just content_length:
    while(i < content_length)
    Any advice!
  4. #3
  5. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,387
    Rep Power
    1871
    First of all, it's [code][/code] tags when posting code.

    > while(i < content_length)
    Where is i getting incremented in your loop - is it being incremented at all.

    > Seems that when in reading from stdin as stream, than there is no EOF, so it is reading continuously.
    Oh you'll get EOF at some point, it's just that your broken code doesn't check for it properly.

    Code:
    fread(s_content, content_length, 1, stdin);
    printf("<p> s_content: %s </p>", s_content);
    There are three things wrong here.
    1. You don't check fread for errors.
    2. You try and use %s to print the result, when there is NO explicit \0 to mark the end of the string.
    3. by saying content_length, 1 you either get a full buffer or nothing at all. It would be better to write it like this.
    Code:
    // There is no need to cast malloc, if this is a C program, and you included stdlib.h
    // +1 gives us room to append a \0
    s_content = malloc(sizeof(char) * (content_length + 1));  
    while ( (n=fread(s_content, 1, content_length, stdin)) != 0 ) {
      s_content[n] = '\0';  // make it a C string
      printf("<p> s_content: %s </p>", s_content);
    }
    > return 1;
    The usual convention is that you return 0 on success and EXIT_FAILURE when things have gone wrong. You seem to have this completely the wrong way round.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    9
    Rep Power
    0
    Thanks for answer Salem!

    Variable i has been incremented, but code has not been post here, sorry. I chech for EOF from stdin in loop:
    Code:
    i = 0; 
      c = getchar(); 
      while(!feof(stdin)) 
      { 
        s_content[i] = c; 
        c = getchar(); 
        printf("%c", c);
        i++; 
      }
    but didnt work, too.
    Not sure if stdin send EOF:
    http://stackoverflow.com/questions/3788722/does-apache-guarantee-that-stdin-will-always-have-an-eof
    I am doing this cgi in c on IIS, dont know if it changes anything.
    Cast to (char *), cause IDE througs IntelliSense: a value of type "void *" cannot be assigned to an entity of type "char *",
    but compiler compile it well.
    And your suggest, i try it and look like:

    Code:
    #include <stdio.h>  /* stdin, printf, fread */
    #include <stdlib.h> /* malloc, getenv */
    #include <ctype.h>  /* isalpha */
    #include <string.h> /* strchr, strcmp */
    
    int main(int argc, char *argv[], char *env[]){
    
    	char *method;	
    	int content_length; 
    	char * s_content;
    	int i, j, n;
    	
    	printf("%s%c%c\n", "Content-Type:text/html;charset=iso-8859-1",13,10);
        // printf("Content-type: text/html \n\n") ; 
        printf(" <html><title>Hello</title><body> \n");   
    
        printf(" <BR><BR><strong> Uploading </strong>\n") ;   
        method = getenv("REQUEST_METHOD");	 
    	printf(" <BR><strong> Method: %s </strong>",  method);
    	
        content_length = atoi(getenv("CONTENT_LENGTH")); 
           if(content_length == 0) 
             return 0; 
    
    	printf("<BR><strong>content_length: %s %d </strong>", getenv("CONTENT_LENGTH"), content_length); 
      
    
    	s_content = malloc(sizeof(char) * (content_length+1)); 
           if(s_content == NULL) 
              return 0; 
    
    	   while ( (n=fread(s_content, 1, content_length, stdin)) != 0 ) {
                     s_content[n] = '\0';  // make it a C string
                     printf("<p> s_content: %s </p>", s_content);
                   }
       
    	   free(s_content);
       printf(" </body></html>");
    
      return 0;
    }
    Still its not working:
    CGI Timeout
    The specified CGI application exceeded the allowed time for processing. The server has deleted the process.
    What i am doing wrong?
  8. #5
  9. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,387
    Rep Power
    1871
    > Cast to (char *), cause IDE througs IntelliSense: a value of type "void *" cannot be assigned to an entity of type "char *",
    Either your IDE is broken, or it somehow believes that the code is C++ code, and not C code.

    Rather than trying to detect EOF, why not use the content length which you have been given?

    Like say
    Code:
    printf("<p> s_content: ");
    for ( i = 0 ; i < content_length && (c = getchar()) != EOF ; i++ ) {
      printf("%c", c);
    }
    printf(" </p>");
    So long as stdin gets at least the number of characters it is expecting, it should exit the loop.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    9
    Rep Power
    0
    Code:
    #include <stdio.h>  /* stdin, printf, fread */
    #include <stdlib.h> /* malloc, getenv */
    #include <ctype.h>  /* isalpha */
    #include <string.h> /* strchr, strcmp */
    
    int main() 
    { 
    int content_length; 
    char * s_content; 
    int i; 
    int c; 
    
      printf("%s%c%c\n", "Content-Type:text/html;charset=iso-8859-1",13,10);    
      printf(" <html><title>hello</title><body> \n");   
      printf(" <BR> Uploading result \n") ;  
    
     content_length = atoi(getenv("CONTENT_LENGTH")); 
      if(content_length == 0) 
        return 0; 
    
      printf("<BR>content_length: %d", content_length); 
      printf("<BR>");	
    
      s_content = (char *) malloc(sizeof(char) * content_length); 
      if(s_content == NULL) 
        return 0; 
    
        printf("<p> s_content: ");
        for ( i = 0 ; i < content_length && (c = getchar()) != EOF ; i++ ) {
          printf("%c", c);
        }
       printf(" </p>");   
      
      if(ferror(stdin)) 
        printf("<BR>ERROR"); 
      else 
        printf("<BR>NO ERROR");
    
      printf("<BR>End i = %d", i); 
    
      free(s_content); 
      printf(" </body></html>");
    
      return 1; 
    }
    It is now reading from stdin, but when a "jpg" file is uploaded,
    there is following output (the size of the file is 3,03 KB):

    Uploading result
    content_length: 3375

    (here is content of s_content: not posted, various characters ...)
    NO ERROR
    End i = 175


    Value of the environment variable "CONTENT_LENGTH"
    differs from the value of the variable "i" at the end of the loop.
    Since i<content_length, seems EOF is getting too early. Why is the
    number of i bytes in loop different from content_length, size of jpeg file?
  12. #7
  13. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,387
    Rep Power
    1871
    Which OS is your CGI server running?
    If it's windows, it might have trouble reading binary streams through stdin.

    On Linux, it works as expected.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main ( ) {
      int i, c;
      while ( (c=getchar()) != EOF ) {
        i++;
      }
      printf("%d bytes read\n", i);
      return 0;
    }
    
    
    $ gcc -Wall foo.c
    $ ls -l monty.jpg 
    -rw-rw-r-- 1 sc sc 9272 2013-07-18 06:38 monty.jpg
    $ ./a.out < monty.jpg 
    9272 bytes read
    Do you have a hex dump utility to hand?
    If not, try this
    Pay particular attention around byte 175 (your i value)

    Comments on this post

    • toni_mc agrees
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  14. #8
  15. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    9
    Rep Power
    0
    My cgi server is IIS 5.1 on Windows OS. Yes, it seems its problem with reading text/binary
    streams through stdin. If reading stdin stream as text, it might be problem if CRFL is reached.
    So, on windows have to turn off the CRLF mapping and set stdin mode to be binary:

    Code:
    #include <io.h>
    #include <fcntl.h>
    _setmode(_fileno(stdin), _O_BINARY);
    Now this works fine:

    Code:
    #include <stdio.h>  
    #include <stdlib.h> 
    #include <ctype.h>  
    #include <string.h> 
    
    #include <io.h>
    #include <fcntl.h>
    
    int main() 
    { 
    int content_length; 
    char * s_content; 
    int i; 
    int c; 
    
      printf("%s%c%c\n", "Content-Type:text/html;charset=iso-8859-1",13,10);    
      printf(" <html><title>hello</title><body> \n");   
      printf(" <BR> Uploading result \n") ;  
    
      // turns off the CRLF mapping.
        _setmode(_fileno(stdin), _O_BINARY);
    
     content_length = atoi(getenv("CONTENT_LENGTH")); 
      if(content_length == 0) 
        return 0; 
    
      printf("<BR>content_length: %d", content_length); 
      printf("<BR>");	
    
      s_content = (char *) malloc(sizeof(char) * content_length); 
      if(s_content == NULL) 
        return 0; 
    
        printf("<p> s_content: ");
        for ( i = 0 ; i < content_length && (c = getchar()) != EOF ; i++ ) {
    		 
            // If file is too big, then server can get stuck in flushing 
            // content to browser and printing it to screen by client.
    		if( content_length < 10000){
                        printf("%c ", c);   	   
    	         // printf("%x ", c);   	   
    		}
        }
       printf(" </p>");   
      
      if(ferror(stdin)) 
        printf("<BR>ERROR"); 
      else 
        printf("<BR>NO ERROR");
    
      printf("<BR>End i = %d", i); 
    
      free(s_content); 
      printf(" </body></html>");
    
      return 1; 
    }
    Thanks!

IMN logo majestic logo threadwatch logo seochat tools logo