/*CHttpSocket.hxx*/
/**********************************************************************
*
* * CSocket class
*
*
* * Capacity
*	- recv, send ÇÔ¼ö¸¦ ÀçÁ¤ÀÇÇØ¼­ ¿øÇÏ´Â Å©±â ¸¸Å­ ¹ÞÀ» ¶§±îÁö loopÃ³¸®
*	- select¸¦ ÀÌ¿ëÇØ timeoutÃ³¸® 
*	- http Request, Respone ±¸Çö
*  
*  
* * History
*   - 2006.08.31 : »ý¼º by newtype 
*   - 2006.11.24 : CHttpSocket::Request      ¸Þ¸ð¸® ¸¯ ¼öÁ¤.
*	- 2007.03.31 : CHttpReqHeader::toString  ¸Þ¸ð¸® µ¤¾î ¾²´Â ¹ö±× ¼öÁ¤
*                  Windows¿¡¼­µµ ÄÄÆÄÀÏ µÇ°Ô ¼öÁ¤
*   - 2007.05.29 : Connection ½ÃÁ¡¿¡µµ timeout Àû¿ë(nonblocking socket»ç¿ë)
*   - 2011.05.13 : Transfer-Encoding: chunked ¸ðµå Áö¿ø
*
**********************************************************************/

#ifndef __CHTTPSOCKET_HEADER_430DFF12_BB12_4922_B61B_C191E71F9D7F__
#define __CHTTPSOCKET_HEADER_430DFF12_BB12_4922_B61B_C191E71F9D7F__

#ifndef WIN32
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <arpa/inet.h>
	#include <netdb.h>
	#include <unistd.h>
#else
	#include <Windows.h>
#endif
#include <stdlib.h>

#define SOCKERR_TIMEOUT			-2
#define SOCKERR_ERROR			-1

#define MAX_HEADER 100		// ÇØ´õ item ÃÑ °¹¼ö
#define MAXBUF	   4096		// ¼ÒÄ¹ ¼Û¼ö½ÅÀÇ ÃÖ´ë Å©±â

#ifndef NULL
	#define NULL 0
#endif

#ifdef WIN32
	#define close closesocket
	#define strlen (int)strlen
	#define socklen_t int
	#define EINPROGRESS WSAEINPROGRESS 
	#define EWOULDBLOCK WSAEWOULDBLOCK 
	#define ETIMEDOUT WSAETIMEDOUT 
	#pragma warning(disable : 4996)
#endif

class CNameValue
{
public:
	CNameValue();
	CNameValue(char *name, char *value);
	~CNameValue();
	void release();

	void set(char *name, char *value);
	char* getName();
	char* getValue();

protected:
	void initMember();

	char			*m_name;
	int				m_nameLength;
	char			*m_value;
	int				m_valueLength;
};

class CnvList 
{
public:
	CnvList();
	~CnvList();

	void add(char *name, char *value);
	char* getValue(char *name);
	void getItem(int index, char *name, int lengthName, char *value, int lengthValue);
	int getSize();

protected:
	CNameValue			*m_list[MAX_HEADER];
	int					m_count;
};

class CHttpHeader : public CnvList
{
public:
	CHttpHeader();
	~CHttpHeader();

	virtual void release();
	virtual bool fromString( char *s )=0;
	virtual void setHeader( char *sp1, char *sp2, char *sp3 )=0;
	virtual char* toString()=0;
	int getStringSize();

	enum HttpMethod { GET = 0, POST };

protected:
	char				*m_header;
	int					m_size;
};

class CHttpReqHeader : public CHttpHeader
{
public:
	CHttpReqHeader();
	CHttpReqHeader(char *method, char *url, char *version);
	~CHttpReqHeader();

	virtual void release();
	virtual bool fromString( char *s );
	virtual void setHeader( char *method, char *url, char *version );
	virtual char* toString();

protected:
	void initMember();

private:
	char				*m_method;
	char				*m_url;
	char				*m_version;
};

class CHttpResHeader : public CHttpHeader
{
public:
	CHttpResHeader();
	CHttpResHeader(char *version, char *resultCode, char *resultMsg);
	~CHttpResHeader();

	virtual void release();
	virtual bool fromString( char *s );
	virtual void setHeader(char *version, char *resultCode, char *resultMsg);
	virtual char* toString();
	int getResultCode();

protected:
	void initMember();

private:
	char				*m_version;
	int					m_resultCode;
	char				*m_resultMsg;
};

class CHttpBody 
{
public:
	CHttpBody();
	~CHttpBody();

	void set(char *body, int size);
	char* toString();

	int getStringSize();

private:
	char				*m_body;
	int					m_size;
};

class CHttpSocket 
{
public:
	CHttpSocket();
	CHttpSocket(int usecTimeout);
	~CHttpSocket();

	void init(int usecTimeout);
	int Connection( const char* host, int port);
	int Request( CHttpReqHeader &header, CHttpBody &body );
	int Response( CHttpResHeader &header, CHttpBody &body );
	void Close();

protected:
	void initMember();

	int Send(char *data, int size);
	int Receive(char *data, int size);

	int recvHeader( CHttpResHeader &header );
	int recvBody( CHttpBody &body );
	int recvBody( CHttpBody &body, int size );

private:
	int connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, struct timeval tval);
	int sendEx(int sock, char *data, int size);
	int recvEx(int sock, char *data, int size);

	int getChunkedLength();

	char*				m_host;
	int					m_port;

	struct timeval		m_timeout;
	int					m_socket;
};

#endif

