From eae6bcfe09af6851d33e482a587745924732949f Mon Sep 17 00:00:00 2001 From: "darin%netscape.com" Date: Fri, 25 May 2001 23:07:44 +0000 Subject: [PATCH] Fixes bug 81008 "support for HTTP/0.9 and folded header lines" r=gagan sr=sfraser a=asa --- .../protocol/http/src/nsHttpResponseHead.cpp | 2 +- .../protocol/http/src/nsHttpTransaction.cpp | 152 ++++++++++-------- netwerk/protocol/http/src/nsHttpTransaction.h | 3 +- 3 files changed, 91 insertions(+), 66 deletions(-) diff --git a/netwerk/protocol/http/src/nsHttpResponseHead.cpp b/netwerk/protocol/http/src/nsHttpResponseHead.cpp index 269253a93a1c..71e442e33efa 100644 --- a/netwerk/protocol/http/src/nsHttpResponseHead.cpp +++ b/netwerk/protocol/http/src/nsHttpResponseHead.cpp @@ -366,7 +366,7 @@ nsHttpResponseHead::ParseVersion(const char *str) // Parse HTTP-Version:: "HTTP" "/" 1*DIGIT "." 1*DIGIT // make sure we have HTTP at the beginning - if (PL_strncmp(str, "HTTP", 4) != 0) { + if (PL_strncasecmp(str, "HTTP", 4) != 0) { LOG(("looks like a HTTP/0.9 response\n")); mVersion = NS_HTTP_VERSION_0_9; return; diff --git a/netwerk/protocol/http/src/nsHttpTransaction.cpp b/netwerk/protocol/http/src/nsHttpTransaction.cpp index 590f621515d7..f8c3b7618e93 100644 --- a/netwerk/protocol/http/src/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/src/nsHttpTransaction.cpp @@ -19,6 +19,7 @@ * * Contributor(s): * Darin Fisher (original author) + * Andreas M. Schneider */ #include "nsHttpHandler.h" @@ -200,12 +201,65 @@ nsHttpTransaction::OnStopTransaction(nsresult status) return NS_OK; } -nsresult +void nsHttpTransaction::ParseLine(char *line) +{ + LOG(("nsHttpTransaction::ParseLine [%s]\n", line)); + + if (!mHaveStatusLine) { + mResponseHead->ParseStatusLine(line); + mHaveStatusLine = PR_TRUE; + // XXX this should probably never happen + if (mResponseHead->Version() == NS_HTTP_VERSION_0_9) + mHaveAllHeaders = PR_TRUE; + } + else + mResponseHead->ParseHeaderLine(line); +} + +void +nsHttpTransaction::ParseLineSegment(char *segment, PRUint32 len) { NS_PRECONDITION(!mHaveAllHeaders, "already have all headers"); - LOG(("nsHttpTransaction::ParseLine [%s]\n", line)); + if (!mLineBuf.IsEmpty() && mLineBuf.Last() == '\n') { + // if this segment is a continuation of the previous... + if (*segment == ' ' || *segment == '\t') { + // trim off the new line char + mLineBuf.Truncate(mLineBuf.Length() - 1); + mLineBuf.Append(segment, len); + } + else { + // trim off the new line char and parse the line + mLineBuf.Truncate(mLineBuf.Length() - 1); + ParseLine((char *) mLineBuf.get()); + // stuff the segment into the line buf + mLineBuf.Assign(segment, len); + } + } + else + mLineBuf.Append(segment, len); + + // a line buf with only a new line char signifies the end of headers. + if (mLineBuf.First() == '\n') { + mHaveAllHeaders = PR_TRUE; + mLineBuf.Truncate(); + } +} + +nsresult +nsHttpTransaction::ParseHead(char *buf, + PRUint32 count, + PRUint32 *countRead) +{ + PRUint32 len; + char *eol; + + LOG(("nsHttpTransaction::ParseHead [count=%u]\n", count)); + + *countRead = 0; + + NS_PRECONDITION(!mHaveAllHeaders, "oops"); // allocate the response head object if necessary if (!mResponseHead) { @@ -214,68 +268,49 @@ nsHttpTransaction::ParseLine(char *line) return NS_ERROR_OUT_OF_MEMORY; } - if (!mHaveStatusLine) { - mResponseHead->ParseStatusLine(line); + // if we don't have a status line and the line buf is empty, then + // this must be the first time we've been called. + if (!mHaveStatusLine && mLineBuf.IsEmpty() && + PL_strncasecmp(buf, "HTTP", PR_MIN(count, 4)) != 0) { + // XXX this check may fail for certain 0.9 content if we haven't + // received at least 4 bytes of data. + mResponseHead->ParseStatusLine(""); mHaveStatusLine = PR_TRUE; - if (mResponseHead->Version() == NS_HTTP_VERSION_0_9) - mHaveAllHeaders = PR_TRUE; - } - else if (*line == '\0') mHaveAllHeaders = PR_TRUE; - else - mResponseHead->ParseHeaderLine(line); - return NS_OK; -} - -nsresult -nsHttpTransaction::ParseHead(char *buf, - PRUint32 count, - PRUint32 *countRead) -{ - char *eol; - - LOG(("nsHttpTransaction::ParseHead [count=%u]\n", count)); - - *countRead = 0; - - NS_PRECONDITION(!mHaveAllHeaders, "oops"); + return NS_OK; + } + // otherwise we can assume that we don't have a HTTP/0.9 response. while ((eol = PL_strnchr(buf, '\n', count - *countRead)) != nsnull) { // found line in range [buf:eol] - *eol = 0; + len = eol - buf + 1; - // actually, in range [buf:eol-1] + *countRead += len; + + // actually, the line is in the range [buf:eol-1] if ((eol > buf) && (*(eol-1) == '\r')) - *(eol-1) = 0; + len--; - // we may have a partial line to complete... - if (!mLineBuf.IsEmpty()) { - mLineBuf.Append(buf); - ParseLine((char *) mLineBuf.get()); - mLineBuf.SetLength(0); - } - else - ParseLine(buf); + buf[len-1] = '\n'; + ParseLineSegment(buf, len); - *countRead += (eol + 1 - buf); - NS_ASSERTION(*countRead <= count, "oops"); + if (mHaveAllHeaders) + return NS_OK; // skip over line buf = eol + 1; - - if (mHaveAllHeaders) - break; } - if (!mHaveAllHeaders && (count > *countRead)) { - // remember this partial line - mLineBuf.Assign(buf, count - *countRead); + // do something about a partial header line + if (!mHaveAllHeaders && (len = count - *countRead)) { *countRead = count; - - LOG(("partial line [%s]\n", mLineBuf.get())); + // ignore a trailing carriage return, and don't bother calling + // ParseLineSegment if buf only contains a carriage return. + if ((buf[len-1] == '\r') && (--len == 0)) + return NS_OK; + ParseLineSegment(buf, len); } - // read something return NS_OK; } @@ -556,27 +591,16 @@ nsHttpTransaction::Read(char *buf, PRUint32 count, PRUint32 *bytesWritten) // we may not have read all of the headers yet... if (!mHaveAllHeaders) { - PRUint32 offset = 0, bytesConsumed; + PRUint32 bytesConsumed = 0; - while (count) { - bytesConsumed = 0; + rv = ParseHead(buf, count, &bytesConsumed); + if (NS_FAILED(rv)) return rv; - rv = ParseHead(buf + offset, count, &bytesConsumed); - if (NS_FAILED(rv)) return rv; + count -= bytesConsumed; - count -= bytesConsumed; - offset += bytesConsumed; - - // see if we're done reading headers - if (mHaveAllHeaders) { - LOG(("have all response headers\n")); - break; - } - } - - if (count) { + if (count && bytesConsumed) { // buf has some content in it; shift bytes to top of buf. - memmove(buf, buf + offset, count); + memmove(buf, buf + bytesConsumed, count); } } diff --git a/netwerk/protocol/http/src/nsHttpTransaction.h b/netwerk/protocol/http/src/nsHttpTransaction.h index 1920fa6d7624..3869a54c4a3b 100644 --- a/netwerk/protocol/http/src/nsHttpTransaction.h +++ b/netwerk/protocol/http/src/nsHttpTransaction.h @@ -84,7 +84,8 @@ public: nsresult OnStopTransaction(nsresult); private: - nsresult ParseLine(char *line); + void ParseLine(char *line); + void ParseLineSegment(char *seg, PRUint32 len); nsresult ParseHead(char *, PRUint32 count, PRUint32 *countRead); nsresult HandleContent(char *, PRUint32 count, PRUint32 *countRead);