diff --git a/mozilla/netwerk/protocol/http/src/Makefile.in b/mozilla/netwerk/protocol/http/src/Makefile.in index a5e4e920bc2..4df4760f82c 100644 --- a/mozilla/netwerk/protocol/http/src/Makefile.in +++ b/mozilla/netwerk/protocol/http/src/Makefile.in @@ -49,6 +49,8 @@ CPPSRCS = \ nsHTTPSHandler.cpp \ $(NULL) +LOCAL_INCLUDES=-I../../../streamconv/converters + EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) include $(topsrcdir)/config/rules.mk diff --git a/mozilla/netwerk/protocol/http/src/makefile.win b/mozilla/netwerk/protocol/http/src/makefile.win index da2a3cb788d..d2526f18972 100644 --- a/mozilla/netwerk/protocol/http/src/makefile.win +++ b/mozilla/netwerk/protocol/http/src/makefile.win @@ -59,7 +59,7 @@ CPP_OBJS= \ .\$(OBJDIR)\nsAuthEngine.obj \ $(NULL) -LOCAL_INCLUDES=-I. +LOCAL_INCLUDES=-I. -I../../../streamconv/converters INCLUDES = $(LOCAL_INCLUDES) @@ -68,6 +68,7 @@ REQUIRES= necko INCS = $(INCS) \ -I$(DEPTH)\dist\include \ -I..\public \ + -I../../../streamconv/converters \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/netwerk/protocol/http/src/nsHTTPResponseListener.cpp b/mozilla/netwerk/protocol/http/src/nsHTTPResponseListener.cpp index e6e93b8bc48..51d927e3c07 100644 --- a/mozilla/netwerk/protocol/http/src/nsHTTPResponseListener.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHTTPResponseListener.cpp @@ -32,6 +32,7 @@ #include "nsCRT.h" #include "nsIStreamConverterService.h" #include "nsIStreamConverter.h" +#include "nsRepository.h" #include "nsHTTPAtoms.h" #include "nsIHttpNotify.h" @@ -224,6 +225,9 @@ nsresult nsHTTPCacheListener::Abort() } +static NS_DEFINE_CID(kSupportsVoidCID, NS_SUPPORTS_VOID_CID); +static NS_DEFINE_IID(kSupportsVoidIID, NS_ISUPPORTSVOID_IID); + //////////////////////////////////////////////////////////////////////////////// // // nsHTTPServerListener Implementation @@ -247,10 +251,11 @@ nsHTTPServerListener::nsHTTPServerListener(nsHTTPChannel* aChannel, nsHTTPHandle { mChannel -> mHTTPServerListener = this; - NS_NewISupportsPRBool (getter_AddRefs (mChunkHeaderEOF)); + nsRepository::CreateInstance (kSupportsVoidCID, NULL, + kSupportsVoidIID, getter_AddRefs (mChunkHeaderEOF)); if (mChunkHeaderEOF) - mChunkHeaderEOF -> SetData (PR_FALSE); + mChunkHeaderEOF -> SetData (&mChunkHeaderCtx); PR_LOG(gHTTPLog, PR_LOG_ALWAYS, ("Creating nsHTTPServerListener [this=%x].\n", this)); @@ -468,6 +473,9 @@ nsHTTPServerListener::OnDataAvailable(nsIChannel* channel, nsXPIDLCString chunkHeader; rv = mResponse -> GetHeader (nsHTTPAtoms::Transfer_Encoding, getter_Copies (chunkHeader)); + nsXPIDLCString trailerHeader; + rv = mResponse -> GetHeader (nsHTTPAtoms::Trailer, getter_Copies (trailerHeader)); + if (NS_SUCCEEDED (rv) && chunkHeader) { NS_WITH_SERVICE (nsIStreamConverterService, @@ -477,8 +485,31 @@ nsHTTPServerListener::OnDataAvailable(nsIChannel* channel, nsString fromStr; fromStr.AssignWithConversion ( chunkHeader ); nsString toStr; toStr.AssignWithConversion ( "unchunked" ); - if (mChunkHeaderEOF) - mChunkHeaderEOF -> SetData (PR_FALSE); + mChunkHeaderCtx.SetEOF (PR_FALSE); + if (trailerHeader) + { + nsCString ts (trailerHeader); + ts.StripWhitespace (); + + char *cp = ts; + + while (*cp) + { + char * pp = PL_strchr (cp , ','); + if (pp == NULL) + { + mChunkHeaderCtx.AddTrailerHeader (cp); + break; + } + else + { + *pp = 0; + mChunkHeaderCtx.AddTrailerHeader (cp); + *pp = ','; + cp = pp + 1; + } + } + } nsCOMPtr converterListener; rv = StreamConvService->AsyncConvertData( @@ -507,13 +538,25 @@ nsHTTPServerListener::OnDataAvailable(nsIChannel* channel, if (NS_FAILED(rv)) return rv; } - PRBool eof = PR_FALSE; - if (mChunkHeaderEOF) - mChunkHeaderEOF -> GetData (&eof); + PRBool eof = mChunkHeaderCtx.GetEOF (); if (mPipelinedRequest && (cl != -1 && cl - mBodyBytesReceived == 0 || eof)) { + if (eof && mResponse) + { + nsVoidArray *mh = mChunkHeaderCtx.GetAllHeaders (); + + for (int i = mh -> Count () - 1; i >= 0; i--) + { + nsHTTPChunkConvHeaderEntry *he = (nsHTTPChunkConvHeaderEntry *) mh -> ElementAt (i); + if (he) + { + nsCOMPtr hAtom = dont_AddRef (NS_NewAtom (he -> mName)); + mResponse -> SetHeader (hAtom, he -> mValue); + } + } + } nsresult rv1 = mPipelinedRequest -> AdvanceToNextRequest (); if (NS_FAILED (rv1)) @@ -580,8 +623,7 @@ nsHTTPServerListener::OnStartRequest (nsIChannel* channel, nsISupports* i_pConte mChannel = nsnull; mResponseDataListener = null_nsCOMPtr (); - if (mChunkHeaderEOF) - mChunkHeaderEOF -> SetData (PR_FALSE); + mChunkHeaderCtx.SetEOF (PR_FALSE); nsHTTPRequest * req; mPipelinedRequest -> GetCurrentRequest (&req); diff --git a/mozilla/netwerk/protocol/http/src/nsHTTPResponseListener.h b/mozilla/netwerk/protocol/http/src/nsHTTPResponseListener.h index 16b729f8dd2..80d61ec481a 100644 --- a/mozilla/netwerk/protocol/http/src/nsHTTPResponseListener.h +++ b/mozilla/netwerk/protocol/http/src/nsHTTPResponseListener.h @@ -26,6 +26,7 @@ #include "nsIChannel.h" #include "nsIStreamListener.h" +#include "nsHTTPChunkConv.h" #include "nsString.h" #include "nsCOMPtr.h" #include "nsIInputStream.h" @@ -124,8 +125,10 @@ protected: PRBool mCompressHeaderChecked; PRBool mChunkHeaderChecked; PRBool mDataReceived; - nsCOMPtr mChunkHeaderEOF; + nsCOMPtr mChunkHeaderEOF; nsHTTPPipelinedRequest* mPipelinedRequest; + + nsHTTPChunkConvContext mChunkHeaderCtx; }; diff --git a/mozilla/netwerk/streamconv/converters/nsHTTPChunkConv.cpp b/mozilla/netwerk/streamconv/converters/nsHTTPChunkConv.cpp index 98457fcb351..ebfd1624d69 100644 --- a/mozilla/netwerk/streamconv/converters/nsHTTPChunkConv.cpp +++ b/mozilla/netwerk/streamconv/converters/nsHTTPChunkConv.cpp @@ -41,6 +41,12 @@ nsHTTPChunkConv::nsHTTPChunkConv() mListener = nsnull; mChunkBuffer = NULL; mState = CHUNK_STATE_INIT; + + mValueBufLen = 0; + mHeaderBufLen= 0; + mHeadersCount= mHeadersExpected = 0; + + mChunkContext= NULL; } nsHTTPChunkConv::~nsHTTPChunkConv () @@ -78,8 +84,14 @@ nsHTTPChunkConv::AsyncConvertData ( mListener = aListener; NS_ADDREF (mListener); - mAsyncConvContext = (nsISupportsPRBool *) aCtxt; - + mAsyncConvContext = (nsISupportsVoid *) aCtxt; + if (mAsyncConvContext) + { + const void *p; + mAsyncConvContext -> GetData (&p); + mChunkContext = (nsHTTPChunkConvContext *)p; + } + return NS_OK; } @@ -200,8 +212,8 @@ nsHTTPChunkConv::OnDataAvailable ( } else { - if (mAsyncConvContext) - mAsyncConvContext -> SetData (PR_TRUE); + if (mChunkContext) + mChunkContext -> SetEOF (PR_TRUE); } mState = CHUNK_STATE_INIT; @@ -254,7 +266,7 @@ nsHTTPChunkConv::OnDataAvailable ( mState = CHUNK_STATE_CR_FINAL; } else - mState = CHUNK_STATE_FINAL; + mState = CHUNK_STATE_TRAILER; c = 0; break; @@ -314,6 +326,58 @@ nsHTTPChunkConv::OnDataAvailable ( streamLen -= rl; } break; + + case CHUNK_STATE_TRAILER: + + if (!mChunkContext || mHeadersCount == mChunkContext -> GetTrailerHeaderCount ()) + mState = CHUNK_STATE_FINAL; + else + mState = CHUNK_STATE_TRAILER_HEADER; + + break; + + case CHUNK_STATE_TRAILER_HEADER: + + rv = iStr -> Read (&c, 1, &rl); + if (NS_FAILED (rv)) + return rv; + + streamLen--; + if (isalnum (c) && mHeaderBufLen < sizeof (mHeaderBuf) - 1) + mHeaderBuf[mHeaderBufLen++] = c; + else + if (c == ':') + { + mHeaderBuf[mHeaderBufLen] = 0; + mState = CHUNK_STATE_TRAILER_VALUE; + } + break; + + case CHUNK_STATE_TRAILER_VALUE: + + rv = iStr -> Read (&c, 1, &rl); + if (NS_FAILED (rv)) + return rv; + + streamLen--; + + if (isspace (c) && mValueBufLen == 0 || c == '\r') + break; + else + if (c == '\n') + { + mValueBuf[mValueBufLen] = 0; + mHeadersCount++; + + mChunkContext -> SetResponseHeader (mHeaderBuf, mValueBuf); + mHeaderBufLen = mValueBufLen = 0; + mState = CHUNK_STATE_TRAILER; + } + else + if (mValueBufLen < sizeof (mValueBuf) - 1) + mValueBuf[mValueBufLen++] = c; + + break; } /* switch */ } /* while */ } /* DO_UNCHUNKING */ @@ -351,3 +415,5 @@ NS_NewHTTPChunkConv (nsHTTPChunkConv ** aHTTPChunkConv) NS_ADDREF(*aHTTPChunkConv); return NS_OK; } + + diff --git a/mozilla/netwerk/streamconv/converters/nsHTTPChunkConv.h b/mozilla/netwerk/streamconv/converters/nsHTTPChunkConv.h index ea5105f8208..a119285e373 100644 --- a/mozilla/netwerk/streamconv/converters/nsHTTPChunkConv.h +++ b/mozilla/netwerk/streamconv/converters/nsHTTPChunkConv.h @@ -26,6 +26,9 @@ #include "nsIStreamConverter.h" #include "nsIFactory.h" #include "nsCOMPtr.h" +#include "nsVoidArray.h" +#include "nsHashtable.h" +#include "nsString.h" #include "nsISupportsPrimitives.h" @@ -54,12 +57,17 @@ typedef enum enum_ChunkState CHUNK_STATE_DATA, CHUNK_STATE_CR_FINAL, CHUNK_STATE_LF_FINAL, - CHUNK_STATE_FINAL + CHUNK_STATE_FINAL, + CHUNK_STATE_TRAILER_HEADER, + CHUNK_STATE_TRAILER_VALUE, + CHUNK_STATE_TRAILER } ChunkState; #define HTTP_CHUNK_TYPE "chunked" #define HTTP_UNCHUNK_TYPE "unchunked" +class nsHTTPChunkConvContext; + class nsHTTPChunkConv : public nsIStreamConverter { public: // nsISupports methods @@ -87,7 +95,94 @@ private: char mLenBuf[20]; PRUint32 mLenBufCnt; - nsCOMPtr mAsyncConvContext; + nsCOMPtr mAsyncConvContext; + + char mValueBuf [4096]; + PRUint32 mValueBufLen; + + char mHeaderBuf [400]; + PRUint32 mHeaderBufLen; + + PRUint32 mHeadersCount; + PRUint32 mHeadersExpected; + + nsHTTPChunkConvContext *mChunkContext; +}; + +class nsHTTPChunkConvHeaderEntry { +public: + + nsHTTPChunkConvHeaderEntry (const char *aName, const char* aValue) + { + mName = aName; + mValue = aValue; + } + + nsHTTPChunkConvHeaderEntry::~nsHTTPChunkConvHeaderEntry() + { + } + + nsCString mName; + nsCString mValue; +}; + +class nsHTTPChunkConvContext { +public: + + nsHTTPChunkConvContext () + : mEof (PR_FALSE), mHeadersCount (0) + { + } + + ~nsHTTPChunkConvContext () + { + PRInt32 i = mHeaders.Count (); + + while (i > 0) + { + nsHTTPChunkConvHeaderEntry *e = (nsHTTPChunkConvHeaderEntry *)mHeaders.RemoveElementAt (i - 1); + delete e; + } + } + + void SetEOF (PRBool eof) + { + mEof = eof; + } + + PRBool GetEOF () { return mEof; } + + nsVoidArray * GetAllHeaders () + { + return &mHeaders; + } + + PRUint32 GetTrailerHeaderCount () + { + return mHeadersCount; + } + + void AddTrailerHeader (const char *header) + { + nsStringKey key (header); + mTrailer.Put (&key, (void *) 1); + + mHeadersCount++; + } + + void SetResponseHeader (const char *header, const char *value) + { + nsHTTPChunkConvHeaderEntry *e = new nsHTTPChunkConvHeaderEntry (header, value); + mHeaders.AppendElement (e); + } + +private: + + PRBool mEof; + nsVoidArray mHeaders; + nsHashtable mTrailer; + + PRUint32 mHeadersCount; };