#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__