possible httpd applet bug?

Denis Vlasenko vda.linux at googlemail.com
Wed Jan 3 14:44:51 PST 2007


On Wednesday 03 January 2007 15:45, Paul Albrecht wrote:
> On Wed, 2007-01-03 at 04:30 +0100, Denis Vlasenko wrote: 
> > On Tuesday 02 January 2007 16:15, Paul Albrecht wrote:
> > > 
> > > I have a question about the way the busybox httpd applet reads cgi
> > > program output: Why is safe_read used rather than full_read?
> > > 
> > > The problem with safe_read is you're not guaranteed the entire first
> > > line of cgi output on the first read so the applet doesn't handle the
> > > status line or content-type header correctly.
> > > 
> > > Seems like if you don't want to read all the cgi output at once, then
> > > you should buffer the first line, but I don't think it makes much of a
> > > difference for busybox httpd.
> > 
> > This code?
> > 
> >                 if (FD_ISSET(inFd, &readSet)) {
> >                         int s = config->accepted_socket;
> >                         char *rbuf = config->buf;
> > 
> > #ifndef PIPE_BUF
> > # define PIPESIZE 4096          /* amount of buffering in a pipe */
> > #else
> > # define PIPESIZE PIPE_BUF
> > #endif
> > #if PIPESIZE >= MAX_MEMORY_BUFF
> > # error "PIPESIZE >= MAX_MEMORY_BUFF"
> > #endif
> > 
> >                         /* There is something to read */
> >                         count = safe_read(inFd, rbuf, PIPESIZE);
> > 
> 
> Yes, this is a problem because safe_read is unbuffered so you can't
> assume you have the first line of output after the initial read, but
> here's what the server does next:
> 
> if (count == 0)
> break;  /* closed */ 
> if (count > 0) {
> 	if (firstLine) {
> 		rbuf[count] = 0;
> 		/* check to see if the user script added headers */
> 		if (strncmp(rbuf, "HTTP/1.0 200 OK\r\n", 4) != 0) {
> 				full_write(s, "HTTP/1.0 200 OK\r\n", 17);
> 		}
> 		/* Sometimes CGI is writing to pipe in small chunks
> 		 * and we don't see Content-type (because the read
> 		 * is too short) and we emit bogus "text/plain"!
> 		 * Is it a bug or CGI *has to* write it in one piece? */
> 		if (strstr(rbuf, "ontent-") == 0) {
> 			full_write(s, "Content-type: text/plain\r\n\r\n", 28);
> 		}
> 		firstLine = 0;
> 	}
> 	if (full_write(s, rbuf, count) != count)
> 		break;
> 
> 	if (DEBUG)
> 		fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf);
> }
> 
> The problem with the preceding code is it assumes the initial safe_read has read at
> least four bytes and that's not guaranteed because safe_read is unbuffered.

Where it assumes that?
> 
> I have worked around the problem by changing the safe_read to full_read so I get all
> the cgi output on the first read.
> 
> If you change the safe_read to a full_read then I don't think you need to write the 
> content-type header, but I haven't tested that yet.

Why I don't have to do it?
--
vda


More information about the busybox mailing list