#ifndef __DCL_HTTP_COLLECTION_H__ #define __DCL_HTTP_COLLECTION_H__ 20050526 #ifndef __DCL_STRING_H__ #include <dcl/core/String.h> #endif #ifndef __DCL_OBJECT_H__ #include <dcl/core/Object.h> #endif #ifndef __DCL_EXCEPTION_H__ #include <dcl/core/Exception.h> #endif #ifndef __DCL_STREAM_H__ #include <dcl/core/Stream.h> #endif #ifndef __DCL_COLLECTION_H__ #include <dcl/core/Collection.h> #endif __DCL_BEGIN_NAMESPACE class HttpServletContext; /* HttpCookieDecoder HttpQueryStringDecoder HttpQueryStringEncoder InputStream HttpFormDataInputStream HttpFormData BufferedHttpFormData StoredHttpFormData HttpFormDataDecoder */ class DCLNAPI HttpCookieDecoder { public: static void decode( StringToStringMap& mapResult, const String& strContents ); }; class DCLNAPI HttpQueryStringDecoder { public: static void decode( StringToStringVectorMap& mapResult, const char* pszQueryString, size_t nLength = (size_t)-1 ); static void decode( StringToStringVectorMap& mapResult, const String& strQueryString ); static bool isValidType( const char* pszContentType ); }; class DCLNAPI HttpQueryStringEncoder { public: static String encode( const StringToStringVectorMap& mapResult ); }; // RFC 1867 - Form-based File Upload in HTML // http://www.faqs.org/rfcs/rfc1867.html class HttpFormDataDecoder; class DCLNAPI HttpFormData : public Object { DECLARE_CLASSINFO(HttpFormData) protected: struct PartHeader { // Content-Disposition String strPartType; // "form-data", "attachement" String strName; // value of "name" String strFileName; // value of "filename" String strContentType; // value of "Content-Type" String strTransferEncoding; // value of "TransferEncoding" }; // PartHeader::strFileName이 있을경우 파일의 시작이다. // 만약 onFileStart내부에서 에러가 발생하여 false를 리턴하면 // 이후의 onFileData, onFileEnd는 호출되지 않는다. virtual bool onFileStart( const PartHeader& header, void** ppCallbackData, String& strCallbackError // return false 이면 ); // formdata의 파일의 데이터가 있을때 불려진다. // 만약 onFileData 내부에서 에러가 발생하여 false를 리턴하면 // onFileEnd 는 호출되지 않는다. 따라서 pCallbackData 관련하여 // 자원이 할당되어 있으면 리턴하기 전에 해제해야 한다. virtual bool onFileData( const void* pData, size_t nSize, void* pCallbackData, String& strCallbackError // return false 이면 ); // 종결 part가 나타나면 불려진다. 종결 part는 CRLF로 구분되며 // 만약 이것이 타나타지 않은 상태에는 bDataSuccess는 false를 넘긴다. virtual bool onFileEnd( const PartHeader& header, void* pCallbackData, bool bDataSuccess, String& strCallbackError // return false 이면 ); friend class HttpFormDataDecoder; }; class DCLNAPI HttpFormDataDecoderException : public Exception { DECLARE_CLASSINFO(HttpFormDataDecoderException) public: enum ErrorCode { ePostReadError, eFormDataCallbackError }; ErrorCode m_errorCode; String m_strMsg; HttpFormDataDecoderException( ErrorCode errorCode, IOException* pDetailEx ); HttpFormDataDecoderException( ErrorCode errorCode, const String& strMsg ); virtual String getMessage() const; }; class DCLNAPI HttpFormDataDecoder : public Object { DECLARE_CLASSINFO(HttpFormDataDecoder) public: static bool isValidType(const char* pszContentType); static String getBoundary(const char* pszContentType); public: HttpFormDataDecoder(size_t nBufferSize = 4096); virtual ~HttpFormDataDecoder(); // 디코딩 과정중에 입력데이터와 관련한 에러가 발생하면 // warnings() 을 통해 에러 메시지를 얻을 수 있다. // 에러가 발생한 데이터는 버려진다. void decode( StringToStringVectorMap& paramResult, HttpFormData* pFileDataResult, InputStream* pInput, const char* pszContentType, size_t nContentLength ) __DCL_THROWS1(HttpFormDataDecoderException*); const String& warnings() const { return m_strWarnings; } private: // NULL : 버퍼가 비어 있거나, not found CRLF char* getLine(size_t& n); // true : valid first part boundary // false : close boundary, or invalid data bool getFirstBoundary(const String& strBoundary); // false EOF bool getPartHeader(HttpFormData::PartHeader& header) __DCL_THROWS1(HttpFormDataDecoderException*); // NULL : 버퍼가 비어 있거나 데이터가 유효하지 않다. enum DataState { dsDataMore, dsBeforeNextBoundary, dsBeforeCloseBoundary }; DataState getDataBlock( char* & pDataStart, size_t& n, // data size const String& strBoundary ); // false data empty && EOF bool readInput() __DCL_THROWS1(HttpFormDataDecoderException*); void appendWarning(const char* pszWarning); InputStream* m_pInput; size_t m_nContentLength; size_t m_nRemainder; char* m_pBuffer; size_t m_nBufferSize; char* m_pDataStart; char* m_pDataEnd; String m_strWarnings; // decoding warnings, string delimeter '\n' // const strings for compare _CONST String m_strContentDisposition; // "Content-Dispositon" _CONST String m_strContentTransferEncoding; // "Content-Transfer-Encoding" _CONST String m_strContentType; // "Content-Type" _CONST String m_strName; // "name" _CONST String m_strFileName; // "filename" }; // 파일데이터를 버퍼에 유지 class DCLNAPI BufferedHttpFormData : public HttpFormData { DECLARE_CLASSINFO(BufferedHttpFormData) public: class FileInfoVector; class DCLNAPI FileInfo { public: String strFileName; // IE는 절대경로 포함, Netscape는 basename String strContentType; String strTransferEncoding; size_t nFileSize; const BYTE* fileData() const { return m_pFileData; } // 파일데이터를 위한 버퍼를 지운다. void freeFileData(); protected: // not using // FileInfo info = v[i]; // use // FileInfo& info = v[i]; FileInfo(); FileInfo(const FileInfo& src); ~FileInfo(); BYTE* m_pFileData; friend class FileInfoVector; friend class BufferedHttpFormData; }; class DCLNAPI FileInfoVector { public: FileInfo& operator[] (int nIndex); int count() const; bool isEmpty() const; const String& name() const { return m_strName; } private: void* m_pHandle; protected: String m_strName; // <input name="name" // not using // FileInfoVector v = formData["name"]; // use // FileInfoVector& v = formData.byName("name"); // or FileInfoVecotr& v = formData[i]; FileInfoVector(const String& strName); FileInfoVector(const FileInfo& src); ~FileInfoVector(); void addTail(FileInfo* pNewItem); friend class BufferedHttpFormData; }; public: BufferedHttpFormData(); virtual ~BufferedHttpFormData(); // <input name="name" type="file"/> 에서 "name" 이 개수 // 서로 다른 "name"의 개수 // FileInfoVector의 개수 int count() const; bool isEmpty() const; FileInfoVector& operator[] (int nIndex); FileInfoVector& byName(const char* pszName); private: void* m_pHandle; void insert(const String& strName, FileInfo* pNewItem); protected: virtual bool onFileStart( const PartHeader& header, void** ppCallbackData, String& strCallbackError // return false 이면 ); virtual bool onFileData( const void* pData, size_t nSize, void* pCallbackData, String& strCallbackError // return false 이면 ); virtual bool onFileEnd( const PartHeader& header, void* pCallbackData, bool bDataSuccess, String& strCallbackError // return false 이면 ); }; // 파일데이터를 임시파일에 저장 class DCLNAPI StoredHttpFormData : public HttpFormData { DECLARE_CLASSINFO(StoredHttpFormData) public: class FileInfoVector; class DCLNAPI FileInfo { public : String strFileName; // basename String strContentType; String strTransferEncoding; size_t nFileSize; String strTempFileName; protected: // not using // FileInfo info = v[i]; // use // FileInfo& info = v[i]; FileInfo(); FileInfo(const FileInfo& str); ~FileInfo(); friend class FileInfoVector; friend class StoredHttpFormData; }; class DCLNAPI FileInfoVector { public: FileInfo& operator[] (int nIndex); int count() const; bool isEmpty() const; const String& name() const { return m_strName; } private: void* m_pHandle; protected: String m_strName; // <input name="name" // not using // FileInfoVector v = formData["name"]; // use // FileInfoVector& v = formData.byName("name"); // or FileInfoVecotr& v = formData[i]; FileInfoVector(const String& strName); FileInfoVector(const FileInfo& src); ~FileInfoVector(); void addTail(FileInfo* pNewItem); friend class StoredHttpFormData; }; public: StoredHttpFormData(const String& strTempDir); virtual ~StoredHttpFormData(); // <input name="name" type="file"/> 에서 "name" 이 개수 // 서로 다른 "name"의 개수 // FileInfoVector의 개수 int count() const; bool isEmpty() const; FileInfoVector& operator[] (int nIndex); FileInfoVector& byName(const char* pszName); private: String m_strTempDir; void* m_pHandle; void insert(const String& strName, FileInfo* pNewItem); protected: virtual bool onFileStart( const PartHeader& header, void** ppCallbackData, String& strCallbackError // return false 이면 ); virtual bool onFileData( const void* pData, size_t nSize, void* pCallbackData, String& strCallbackError // return false 이면 ); virtual bool onFileEnd( const PartHeader& header, void* pCallbackData, bool bDataSuccess, String& strCallbackError // return false 이면 ); }; __DCL_END_NAMESPACE #endif // __DCL_HTTP_COLLECTION_H__