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