nsresult nsHttpTransaction::ParseHead(char *buf, PRUint32 count, PRUint32 *countRead) { nsresult rv; 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) { mResponseHead = new nsHttpResponseHead(); if (!mResponseHead) return NS_ERROR_OUT_OF_MEMORY; // report that we have a least some of the response if (mActivityDistributor) mActivityDistributor->ObserveActivity( mChannel, NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION, NS_HTTP_ACTIVITY_SUBTYPE_RESPONSE_START, PR_Now(), LL_ZERO, EmptyCString()); } // 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()) { // tolerate some junk before the status line char *p = LocateHttpStart(buf, PR_MIN(count, 8)); if (!p) { // Treat any 0.9 style response of a put as a failure. if (mRequestHead->Method() == nsHttp::Put) return NS_ERROR_ABORT; mResponseHead->ParseStatusLine(""); mHaveStatusLine = PR_TRUE; mHaveAllHeaders = PR_TRUE; return NS_OK; } if (p > buf) { // skip over the junk *countRead = p - buf; buf = p; } } // otherwise we can assume that we don't have a HTTP/0.9 response. while ((eol = static_cast<char *>(memchr(buf, '\n', count - *countRead))) != nsnull) { // found line in range [buf:eol] len = eol - buf + 1; *countRead += len; // actually, the line is in the range [buf:eol-1] if ((eol > buf) && (*(eol-1) == '\r')) len--; buf[len-1] = '\n'; rv = ParseLineSegment(buf, len); if (NS_FAILED(rv)) return rv; if (mHaveAllHeaders) return NS_OK; // skip over line buf = eol + 1; } // do something about a partial header line if (!mHaveAllHeaders && (len = count - *countRead)) { *countRead = count; // 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; rv = ParseLineSegment(buf, len); if (NS_FAILED(rv)) return rv; } return NS_OK; }
nsresult nsHttpTransaction::ParseHead(char *buf, PRUint32 count, PRUint32 *countRead) { nsresult rv; 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) { mResponseHead = new nsHttpResponseHead(); if (!mResponseHead) return NS_ERROR_OUT_OF_MEMORY; // report that we have a least some of the response if (mActivityDistributor) mActivityDistributor->ObserveActivity( mChannel, NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION, NS_HTTP_ACTIVITY_SUBTYPE_RESPONSE_START, PR_Now(), LL_ZERO, EmptyCString()); } if (!mHttpResponseMatched) { // Normally we insist on seeing HTTP/1.x in the first few bytes, // but if we are on a persistent connection and the previous transaction // was not supposed to have any content then we need to be prepared // to skip over a response body that the server may have sent even // though it wasn't allowed. if (!mConnection || !mConnection->LastTransactionExpectedNoContent()) { // tolerate only minor junk before the status line mHttpResponseMatched = true; char *p = LocateHttpStart(buf, NS_MIN<PRUint32>(count, 11), true); if (!p) { // Treat any 0.9 style response of a put as a failure. if (mRequestHead->Method() == nsHttp::Put) return NS_ERROR_ABORT; mResponseHead->ParseStatusLine(""); mHaveStatusLine = true; mHaveAllHeaders = true; return NS_OK; } if (p > buf) { // skip over the junk mInvalidResponseBytesRead += p - buf; *countRead = p - buf; buf = p; } } else { char *p = LocateHttpStart(buf, count, false); if (p) { mInvalidResponseBytesRead += p - buf; *countRead = p - buf; buf = p; mHttpResponseMatched = true; } else { mInvalidResponseBytesRead += count; *countRead = count; if (mInvalidResponseBytesRead > MAX_INVALID_RESPONSE_BODY_SIZE) { LOG(("nsHttpTransaction::ParseHead() " "Cannot find Response Header\n")); // cannot go back and call this 0.9 anymore as we // have thrown away a lot of the leading junk return NS_ERROR_ABORT; } return NS_OK; } } } // otherwise we can assume that we don't have a HTTP/0.9 response. NS_ABORT_IF_FALSE (mHttpResponseMatched, "inconsistent"); while ((eol = static_cast<char *>(memchr(buf, '\n', count - *countRead))) != nsnull) { // found line in range [buf:eol] len = eol - buf + 1; *countRead += len; // actually, the line is in the range [buf:eol-1] if ((eol > buf) && (*(eol-1) == '\r')) len--; buf[len-1] = '\n'; rv = ParseLineSegment(buf, len); if (NS_FAILED(rv)) return rv; if (mHaveAllHeaders) return NS_OK; // skip over line buf = eol + 1; if (!mHttpResponseMatched) { // a 100 class response has caused us to throw away that set of // response headers and look for the next response return NS_ERROR_NET_INTERRUPT; } } // do something about a partial header line if (!mHaveAllHeaders && (len = count - *countRead)) { *countRead = count; // 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; rv = ParseLineSegment(buf, len); if (NS_FAILED(rv)) return rv; } return NS_OK; }