www-apache-bugdb mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From W Rowe <wr...@lnd.com>
Subject os-windows/5671: CGI print to stdout while reading POST from stdin deadlocks Win32 Pipes
Date Sun, 30 Jan 2000 15:22:36 GMT

>Number:         5671
>Category:       os-windows
>Synopsis:       CGI print to stdout while reading POST from stdin deadlocks Win32 Pipes
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    apache
>State:          open
>Class:          duplicate
>Submitter-Id:   apache
>Arrival-Date:   Sun Jan 30 07:30:00 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     wrowe@lnd.com
>Release:        1.3.11
>Organization:
apache
>Environment:
Win32 NT 4.0 SP4
>Description:
A number of users have reported odd CGI behavior of their scripts locking up the application
and an Apache process if the file processes a large POST submission at the same time it is
streaming a large response to stdout.

Any CGI program, Perl/C/etc... can create this behavior.  Using FORM INPUT TYPE=FILE to send
a large file (greater than the 2000 byte buffer - including the headers) - while providing
continual feedback that is flushed to the pipe (that grows beyond the pipe buffer length)
deadlocks the write operations from both the application and Apache.  Since neither app is
listening, the full buffers deadlock both apps.

module buff.c lns 304-311 --

/* the lowest level writing primitive */
static int ap_write(BUFF *fb, const void *buf, int nbyte)
{
    int rv;
    
#ifdef WIN32
    if (fb->hFH != INVALID_HANDLE_VALUE) {
        if (!WriteFile(fb->hFH,buf,nbyte,&rv,NULL)) {

-- end module buff.c lns 304-311

Apache freezes at WriteFile above.
>How-To-Repeat:
Code example CGIDump.c ----

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

/* For _setmode binary MS-DOS semantics: */
#include <fcntl.h>
#include <io.h>

const char hex[16] = "0123456789abcdef";


int main(int argc, char **argv, char **argenv)
{
    char *server_protocol = NULL, *server_software = NULL;
    char *content_type = NULL;
    unsigned long content_length = 0;
    unsigned char strbuf[16], outbuf[80];
    unsigned long off, offset = 0;
    int i, len, acnt;
    char **aptr, **ignptr;
    
    /* For _setmode binary MS-DOS semantics: */
    _setmode(_fileno(stdin), _O_BINARY);

    aptr = argenv;
    while (*aptr)
    {
        if (strncmp("CONTENT_TYPE=", *aptr, 13) == 0)
            content_type = *aptr + 13;
        else if (strncmp("CONTENT_LENGTH=", *aptr, 15) == 0)
            content_length = strtoul(*aptr + 15, ignptr, 10);
        ++aptr;
    }

    if (!server_protocol || !server_software)
    {
        fputs("Missing CGI Environment Values!", stderr);
        exit(1);
    }

    puts("Content-type: text/plain\n");

    fflush(stdout);

    puts("Command Line Arguments:\n");
    acnt = argc; aptr = argv;
	while (acnt-- && *aptr)
        puts(*(aptr++));

    fflush(stdout);
    
    puts("\nEnvironmental Values:\n");
    aptr = argenv;
	while (*aptr)
        puts(*(aptr++));
    
    fflush(stdout);
      
    puts("\nInput Stream (POST):\n");
    while (-1)
    {
        len = 0;
        while (offset + len < content_length && len < sizeof(strbuf))
        {
            if (!fread(strbuf, 1, 1, stdin)) break;
            ++len;
        }
        memset(outbuf, ' ', sizeof(outbuf));
        outbuf[76] = '\0';
        for (i = 8, off = offset; i--; off >>= 4)
            outbuf[i] = hex[off & 0x0f];
        for (i = 0; i < len; ++i)
            outbuf[i * 3 + 10] = hex[strbuf[i] >> 4],
            outbuf[i * 3 + 11] = hex[strbuf[i] & 0x0f],
            outbuf[i + 59] = (strbuf[i] < 32 || strbuf[i] > 126) ? '.' : strbuf[i];
        puts(outbuf);
        offset += len;
        if (!(offset | 0x3f))
            fflush(stdout);
        if (ferror(stdin) || feof(stdin))
            break;
    }
    
    printf("\nTotal Stream Length: %ld\n", offset);
    fflush(stdout);

    return 0;
}

--- end example code
>Fix:
CGI coders: _Don't_ write while reading the POST submission!!!  Remember after you have written
about 2000 bytes to the stdout stream (count your lf's as 2 - cr+lf) - the system WILL lock!
 It's safe to write just the receipt header (it's still buffered for now) - but hold your
response for the end of the file!

Apache: Yes - use async pipes (obviously) - but I will review the code and look at implementation.
 It's not the NT port that I'm stumbling over - it's understanding the intent of the original
Unix implementation ;^/
>Release-Note:
>Audit-Trail:
>Unformatted:
 [In order for any reply to be added to the PR database, you need]
 [to include <apbugs@Apache.Org> in the Cc line and make sure the]
 [subject line starts with the report component and number, with ]
 [or without any 'Re:' prefixes (such as "general/1098:" or      ]
 ["Re: general/1098:").  If the subject doesn't match this       ]
 [pattern, your message will be misfiled and ignored.  The       ]
 ["apbugs" address is not added to the Cc line of messages from  ]
 [the database automatically because of the potential for mail   ]
 [loops.  If you do not include this Cc, your reply may be ig-   ]
 [nored unless you are responding to an explicit request from a  ]
 [developer.  Reply only with text; DO NOT SEND ATTACHMENTS!     ]
 
 


Mime
View raw message