Add initial implementation of http/1.1 chunk-encoding converters. Not

included into the build for the time being.
This commit is contained in:
ruslan%netscape.com 2000-02-22 01:46:23 +00:00
parent ec5ba812cc
commit 39972a5e0c
2 changed files with 410 additions and 0 deletions

View File

@ -0,0 +1,321 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): ruslan
*/
#include "nsHTTPChunkConv.h"
#include "nsIAllocator.h"
#include "plstr.h"
#include "prlog.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsIStringStream.h"
#include "nsIStreamListener.h"
#include "nsIStringStream.h"
#include <ctype.h>
// nsISupports implementation
NS_IMPL_ISUPPORTS2 (nsHTTPChunkConv, nsIStreamConverter, nsIStreamListener);
// nsFTPDirListingConv methods
nsHTTPChunkConv::nsHTTPChunkConv()
{
NS_INIT_ISUPPORTS ();
mListener = nsnull;
mChunkBuffer = NULL;
}
nsHTTPChunkConv::~nsHTTPChunkConv ()
{
NS_IF_RELEASE(mListener);
if (mChunkBuffer != NULL)
nsAllocator::Free (mChunkBuffer);
}
NS_IMETHODIMP
nsHTTPChunkConv::AsyncConvertData (
const PRUnichar *aFromType,
const PRUnichar *aToType,
nsIStreamListener *aListener,
nsISupports *aCtxt)
{
nsString2 from (aFromType);
nsString2 to ( aToType );
char * fromStr = from.ToNewCString ();
char * toStr = to.ToNewCString ();
if (!PL_strncasecmp (fromStr, HTTP_CHUNK_TYPE, strlen (HTTP_CHUNK_TYPE ) )
&&
!PL_strncasecmp (toStr, HTTP_UNCHUNK_TYPE, strlen (HTTP_UNCHUNK_TYPE)))
mMode = DO_CHUNKING;
else
mMode = DO_UNCHUNKING;
nsAllocator::Free (fromStr);
nsAllocator::Free ( toStr);
// hook ourself up with the receiving listener.
mListener = aListener;
NS_ADDREF (mListener);
return NS_OK;
}
NS_IMETHODIMP
nsHTTPChunkConv::OnStartRequest (nsIChannel *aChannel, nsISupports *aContext)
{
return mListener -> OnStartRequest (aChannel, aContext);
}
NS_IMETHODIMP
nsHTTPChunkConv::OnStopRequest (nsIChannel *aChannel, nsISupports *aContext, nsresult status, const PRUnichar *errorMsg)
{
return mListener -> OnStopRequest (aChannel, aContext, status, errorMsg);
}
NS_IMETHODIMP
nsHTTPChunkConv::OnDataAvailable (
nsIChannel *aChannel,
nsISupports *aContext,
nsIInputStream *iStr,
PRUint32 aSourceOffset,
PRUint32 aCount)
{
nsresult rv = NS_ERROR_FAILURE;
PRUint32 rl;
PRUint32 streamLen;
char c;
rv = iStr -> Available (&streamLen);
if (NS_FAILED (rv))
return rv;
if (streamLen == 0)
return NS_OK;
if (mMode == DO_CHUNKING)
{
mChunkBuffer = (char * )nsAllocator::Alloc (streamLen + 20);
mChunkBufferPos = sprintf (mChunkBuffer, "%x%c%c", streamLen, '\r', '\n');
rv = iStr -> Read (&mChunkBuffer[mChunkBufferPos], streamLen, &rl);
if (NS_FAILED (rv))
return rv;
mChunkBufferPos += streamLen;
mChunkBuffer[mChunkBufferPos++] = '\r';
mChunkBuffer[mChunkBufferPos++] = '\n';
mChunkBuffer[mChunkBufferPos ] = 0;
mChunkBufferLength = mChunkBufferPos;
nsIInputStream * convertedStream = nsnull;
nsCString convertedString (mChunkBuffer);
nsISupports * convertedStreamSup = nsnull;
rv = NS_NewStringInputStream (&convertedStreamSup, convertedString);
if (NS_FAILED (rv))
return rv;
rv = convertedStreamSup -> QueryInterface (NS_GET_IID (nsIInputStream), (void**)&convertedStream);
NS_RELEASE (convertedStreamSup);
if (NS_FAILED (rv))
return rv;
rv = mListener -> OnDataAvailable (aChannel, aContext, convertedStream, aSourceOffset, mChunkBufferLength);
if (NS_FAILED (rv))
return rv;
}
else
{
// DO_UNCHUNKING
while (streamLen > 0)
{
switch (mState)
{
case CHUNK_STATE_INIT:
if (mChunkBuffer != NULL)
{
nsAllocator::Free (mChunkBuffer);
mChunkBuffer = NULL;
}
mChunkBufferPos = mChunkBufferLength = 0;
mLenBufCnt = 0;
mState = CHUNK_STATE_LENGTH;
break;
case CHUNK_STATE_FINAL:
// send data upstream
{
nsIInputStream * convertedStream = nsnull;
nsCString convertedString (mChunkBuffer);
nsISupports * convertedStreamSup = nsnull;
rv = NS_NewStringInputStream (&convertedStreamSup, convertedString);
if (NS_FAILED (rv))
return rv;
rv = convertedStreamSup -> QueryInterface (NS_GET_IID(nsIInputStream), (void**)&convertedStream);
NS_RELEASE (convertedStreamSup);
if (NS_FAILED (rv))
return rv;
rv = mListener -> OnDataAvailable (aChannel, aContext, convertedStream, aSourceOffset, mChunkBufferLength);
if (NS_FAILED (rv))
return rv;
mState = CHUNK_STATE_INIT;
if (mChunkBuffer != NULL)
{
nsAllocator::Free (mChunkBuffer);
mChunkBuffer = NULL;
}
}
break;
case CHUNK_STATE_CR:
case CHUNK_STATE_CR_FINAL:
rv = iStr -> Read (&c, 1, &rl);
if (NS_FAILED (rv))
return rv;
if (c != '\r')
return NS_ERROR_FAILURE;
streamLen--;
mState = mState == CHUNK_STATE_CR ? CHUNK_STATE_LF : CHUNK_STATE_LF_FINAL;
break;
case CHUNK_STATE_LF:
case CHUNK_STATE_LF_FINAL:
rv = iStr -> Read (&c, 1, &rl);
if (NS_FAILED (rv))
return rv;
if (c != '\n')
return NS_ERROR_FAILURE;
streamLen--;
if (mState == CHUNK_STATE_LF)
{
mChunkBuffer = (char * )nsAllocator::Alloc (mChunkBufferLength + 1);
mState = CHUNK_STATE_DATA;
}
else
mState = CHUNK_STATE_FINAL;
break;
case CHUNK_STATE_LENGTH:
if (mLenBufCnt >= sizeof (mLenBuf) - 1)
return NS_ERROR_FAILURE;
rv = iStr -> Read (&c, 1, &rl);
if (NS_FAILED (rv))
return rv;
streamLen--;
if (isxdigit (c))
mLenBuf[mLenBufCnt++] = c;
else
{
mLenBuf[mLenBufCnt] = 0;
sscanf (mLenBuf, "%x", &mChunkBufferLength);
mState = CHUNK_STATE_CR;
}
break;
case CHUNK_STATE_DATA:
if (mChunkBufferLength - mChunkBufferPos <= streamLen)
{
// entire chunk
rv = iStr -> Read (&mChunkBuffer[mChunkBufferPos], mChunkBufferLength - mChunkBufferPos, &rl);
if (NS_FAILED (rv))
return rv;
mChunkBufferPos += rl;
mChunkBuffer[mChunkBufferPos++] = 0;
streamLen -= rl;
mState = CHUNK_STATE_CR_FINAL;
}
else
{
rv = iStr -> Read (&mChunkBuffer[mChunkBufferPos], streamLen, &rl);
if (NS_FAILED (rv))
return rv;
mChunkBufferPos += rl;
streamLen -= rl;
}
break;
} /* switch */
} /* while */
} /* DO_UNCHUNKING */
return NS_OK;
} /* OnDataAvailable */
// XXX/ruslan: need to implement this too
NS_IMETHODIMP
nsHTTPChunkConv::Convert (
nsIInputStream *aFromStream,
const PRUnichar *aFromType,
const PRUnichar *aToType,
nsISupports *aCtxt,
nsIInputStream **_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
NS_NewHTTPChunkConv (nsHTTPChunkConv ** aHTTPChunkConv)
{
NS_PRECONDITION(aHTTPChunkConv != nsnull, "null ptr");
if (! aHTTPChunkConv)
return NS_ERROR_NULL_POINTER;
*aHTTPChunkConv = new nsHTTPChunkConv ();
if (! *aHTTPChunkConv)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aHTTPChunkConv);
return NS_OK;
}

View File

@ -0,0 +1,89 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#if !defined (__nsHTTPChunkConv__h__)
#define __nsHTTPChunkConv__h__ 1
#include "nsIStreamConverter.h"
#include "nsIFactory.h"
#define NS_HTTPCHUNKCONVERTER_CID \
{ \
/* 95ca98d9-2a96-48d6-a014-0dffa84834a1 */ \
0x95ca98d9, \
0x2a96, \
0x48d6, \
{0xa0, 0x14, 0x0d, 0xff, 0xa8, 0x48, 0x34, 0xa1}\
}
static NS_DEFINE_CID(kHTTPChunkConverterCID, NS_HTTPCHUNKCONVERTER_CID);
typedef enum emum_ChunkMode
{
DO_CHUNKING, DO_UNCHUNKING
} ChunkMode;
typedef enum enum_ChunkState
{
CHUNK_STATE_INIT,
CHUNK_STATE_CR,
CHUNK_STATE_LF,
CHUNK_STATE_LENGTH,
CHUNK_STATE_DATA,
CHUNK_STATE_CR_FINAL,
CHUNK_STATE_LF_FINAL,
CHUNK_STATE_FINAL,
} ChunkState;
#define HTTP_CHUNK_TYPE "chunked"
#define HTTP_UNCHUNK_TYPE "unchunked"
class nsHTTPChunkConv : public nsIStreamConverter {
public:
// nsISupports methods
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMOBSERVER
NS_DECL_NSISTREAMLISTENER
// nsIStreamConverter methods
NS_DECL_NSISTREAMCONVERTER
nsHTTPChunkConv ();
virtual ~nsHTTPChunkConv ();
private:
nsIStreamListener *mListener; // this guy gets the converted data via his OnDataAvailable ()
ChunkState mState;
ChunkMode mMode;
char *mChunkBuffer;
PRUint32 mChunkBufferLength;
PRUint32 mChunkBufferPos;
char mLenBuf[20];
PRUint32 mLenBufCnt;
};
#endif