fielding 97/04/19 21:02:09
Modified: src CHANGES http_protocol.c
Log:
Work around a bug in Netscape Navigator versions 2.x, 3.x and 4.0b2's
parsing of headers. If the terminating empty-line CRLF occurs starting
at the 256th or 257th byte of output, then Navigator will think a normal
image is invalid. We are guessing that this is because their initial
read of a new request uses a 256 byte buffer. We check the bytes written
so far and, if we are about to tickle the bug, we instead insert a
padding header of eminent bogosity.
Submitted by: Roy Fielding and Dean Gaudet, PR#232
Reviewed by: Ken Coar
Revision Changes Path
1.238 +8 -0 apache/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apache/src/CHANGES,v
retrieving revision 1.237
retrieving revision 1.238
diff -C3 -r1.237 -r1.238
*** CHANGES 1997/04/18 02:56:13 1.237
--- CHANGES 1997/04/20 04:02:07 1.238
***************
*** 1,5 ****
--- 1,13 ----
Changes with Apache 1.2
+ *) Work around a bug in Netscape Navigator versions 2.x, 3.x and 4.0b2's
+ parsing of headers. If the terminating empty-line CRLF occurs starting
+ at the 256th or 257th byte of output, then Navigator will think a
normal
+ image is invalid. We are guessing that this is because their initial
+ read of a new request uses a 256 byte buffer. We check the bytes
written
+ so far and, if we are about to tickle the bug, we instead insert a
+ padding header of eminent bogosity. [Roy Fielding and Dean Gaudet]
PR#232
+
*) Fixed SIGSEGV problem when a DirectoryIndex file is also the source
of an external redirection. [Roy Fielding and Paul Sutton]
1.114 +34 -3 apache/src/http_protocol.c
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.c,v
retrieving revision 1.113
retrieving revision 1.114
diff -C3 -r1.113 -r1.114
*** http_protocol.c 1997/04/12 04:24:57 1.113
--- http_protocol.c 1997/04/20 04:02:08 1.114
***************
*** 1053,1058 ****
--- 1053,1086 ----
table_unset(r->headers_out, "Server");
}
+ /* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2
+ * have a header parsing bug. If the terminating \r\n occur starting
+ * at the 256th or 257th byte of output then it will not properly parse
+ * the headers. Curiously it doesn't exhibit this problem at 512, 513.
+ * We are guessing that this is because their initial read of a new request
+ * uses a 256 byte buffer, and subsequent reads use a larger buffer.
+ * So the problem might exist at different offsets as well.
+ *
+ * This should also work on keepalive connections assuming they use the
+ * same small buffer for the first read of each new request.
+ *
+ * At any rate, we check the bytes written so far and, if we are about to
+ * tickle the bug, we instead insert a bogus padding header. Since the bug
+ * manifests as a broken image in Navigator, users blame the server. :(
+ * It is more expensive to check the User-Agent than it is to just add the
+ * bytes, so we haven't used the BrowserMatch feature here.
+ */
+ static void terminate_header (BUFF *client)
+ {
+ long int bs;
+
+ bgetopt(client, BO_BYTECT, &bs);
+ if (bs == 256 || bs == 257)
+ bputs("X-Pad: avoid browser bug\015\012", client);
+
+ bputs("\015\012", client); /* Send the terminating empty line */
+ }
+
static char *make_allow(request_rec *r)
{
int allowed = r->allowed;
***************
*** 1114,1120 ****
table_do((int (*)(void *, const char *, const char *))send_header_field,
(void *)r, r->headers_out, NULL);
! bputs("\015\012", r->connection->client);
kill_timeout(r);
bsetopt(r->connection->client, BO_BYTECT, &zero);
--- 1142,1149 ----
table_do((int (*)(void *, const char *, const char *))send_header_field,
(void *)r, r->headers_out, NULL);
!
! terminate_header(r->connection->client);
kill_timeout(r);
bsetopt(r->connection->client, BO_BYTECT, &zero);
***************
*** 1207,1213 ****
table_do((int (*)(void *, const char *, const char *))send_header_field,
(void *)r, r->headers_out, NULL);
! bputs("\015\012", r->connection->client);
kill_timeout(r);
--- 1236,1243 ----
table_do((int (*)(void *, const char *, const char *))send_header_field,
(void *)r, r->headers_out, NULL);
!
! terminate_header(r->connection->client);
kill_timeout(r);
***************
*** 1630,1636 ****
"Warning",
"WWW-Authenticate",
NULL);
! bputs("\015\012", fd);
kill_timeout(r);
return;
--- 1660,1667 ----
"Warning",
"WWW-Authenticate",
NULL);
!
! terminate_header(r->connection->client);
kill_timeout(r);
return;