// WMSOAPClientConn.h: interface for the WMSOAPClientConn class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003 Robert Cunnings. All rights reserved.
//
// You may copy, modify, distribute or publish this code free of charge.
//
// NO WARRANTY: This software is provided AS IS, without warranty of any kind.
//
//////////////////////////////////////////////////////////////////////
//
// WMSOAPClientConn class - a class for HTTP protocol support.
// Uses Winsock2, supports HTTP Version 1.0.
// 
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_WMSOAPCLIENTCONN_H__CC9DCCCB_876B_47FF_A8C1_88DC96EFE044__INCLUDED_)
#define AFX_WMSOAPCLIENTCONN_H__CC9DCCCB_876B_47FF_A8C1_88DC96EFE044__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "WMConnection.h"
#include "WMEventHandler.h"
#include "WMStateMachine.h"
#include "WMLogRec.h"
#include "dimeparser.h"
#include <time.h>
#include <deque>
using namespace std;

#define FILE_BUF_SIZE 4096
#define HEADER_LINE_SIZE 256

class WMSOAPListener;
class SOAPSvcDesc;

class WMSOAPClientConn : public WMEventHandler
{
public:
	WMSOAPClientConn();
	WMSOAPClientConn(WMSOAPListener *pServer, ULONG uIndex);
	virtual ~WMSOAPClientConn();

	// abstract base class virtual method definition
	int InitializeStateMachine();
	// event object processing called from threadproc
	void OnIOCompletion(DWORD dwNumBytes);
	// termination helper
	void Terminate();
	// called by server
	BOOL Initialize(SOCKET s);
	// socket connection
	WMConnection m_Connection;
	// pointer to server
	WMSOAPListener *m_pServer;

	enum METHOD_TYPE
	{
		METHOD_UNSUPPORTED = 0,
		METHOD_GET,     // RFP 1945 10.1
		METHOD_HEAD,    // RFP 1945 10.2
		METHOD_POST,    // RFP 1945 10.3
		METHOD_PUT,     // RFP 1945 D.1.1
		METHOD_DELETE,  // RFP 1945 D.1.2
		METHOD_LINK,    // RFP 1945 D.1.3
		METHOD_UNLINK,  // RFP 1945 D.1.4
	};

	struct tagMethodTable
	{
		enum METHOD_TYPE nID;
		char *pszKey;
	};

protected:
	// implementation
	ULONG		m_uListenerIndex;       // index into array of client objects held by listener
	COMLOGREC	m_LogRec;               // Common Log Format record
	WSABUF		m_RcvBuffer;            // receive buffer
	int			m_nLastInternalError;   // error id

	typedef deque<LPWSABUF, allocator<LPWSABUF> > dequeWriteQueue;
	dequeWriteQueue m_WriteQueue; // socket asynch write queue

	// the embedded state machine 
	WMStateMachine m_StateMachine;

	// thread synchronization
	CRITICAL_SECTION m_CSWriteQueue;

	// state machine actions
	int ACT_HdrRead();
	int ACT_BodyRead();
	int ACT_SimpleRequest();
	int ACT_FullRequest();
	int ACT_ReadEntityBody();
	int ACT_ProcessRequest();
	int ACT_SendData();
	int ACT_DataSent();
	int ACT_RequestError();
	int ACT_MethodError();
	int ACT_NotFoundError();
	int ACT_NotAvailableError();
	int ACT_HTTPVersionError();
	int ACT_ForbiddenError();
	int ACT_InternalError();
	int ACT_NetworkError();
	int ACT_Terminated();

	// helpers for servicing client request
	int ParseRequestLine();
	int URLDecodeString(string& str,
						   LPSTR pszBuffer,
						   int nStart, int nStop);
	int ParseHeader();
	int WriteLog();
	int Process_GET();
	int Process_HEAD();
	int Process_POST();
	int Process_PUT();
	int Process_DELETE();
	int DoSOAPPost(SOAPSvcDesc *pSvc);
	int DoSOAPGet(SOAPSvcDesc *pSvc);

    SOAPSvcDesc *FindServiceMapEntry();
    IDispatch *GetWSDLClient(SOAPSvcDesc *pSvc);

	bool ParseURI();
	bool ParseContentType(  string& strFieldBody,
							string& strContentType,
							map<string, string>& mapParams);
	bool ParseParameters(string& strParams, map<string, string>& mapParams);
	bool StripComments(string& strFieldBody);
	void TrimWhitespace(string& strData);
	void LeftTrim(string& strData);
	void RightTrim(string& strData);
	enum MIMEContentType {
		Content_Type_Empty = 0,
		Content_Type_Text_XML,
		Content_Type_Application_SOAP_XML,
		Content_Type_Application_DIME
	};
	BOOL ReadSocket();
	BOOL ReadSocketDIME();
	BOOL SendData(const char *pszData, size_t NumBytes);
	BOOL SendData(HANDLE hFile);
	int SendFile(BOOL bHeaderOnly = FALSE);
	int SendSOAPOutput(  const char *pszOutput,
						 unsigned long ulLength,
						 int nHTTPStatus,
                         BOOL bHeaderOnly = FALSE);
	int SendSOAPEndpointGETResponse(BOOL bHeaderOnly = FALSE);
	int SendDIMEOutput(int nHTTPStatus, BOOL bHeaderOnly = FALSE);
	BOOL SendCannedMsg(int nError, ...);
	BOOL StringToFileTime(string& strTime, LPFILETIME pFileTime);
	BOOL SendReplyHeader(const string& strContentType,
							HANDLE hFile,
							BY_HANDLE_FILE_INFORMATION& FileTime);
	BOOL SendSOAPReplyHeader(int nHTTPStatus, DWORD dwContentLength);
	BOOL SendDIMEReplyHeader(int nHTTPStatus, unsigned long ulContentLength);
	BOOL Send204Response();
	BOOL Send304Response();

	char			*m_pszBuffer;  // request buffer
	DWORD			m_dwIndex; // index into receive buffer
	DWORD			m_dwEntityBodyLength; // entity-body length
	list<string>	m_listRequestStrings; // list of raw request strings
	METHOD_TYPE		m_nMethod;  //  requested method
	string			m_strMethod;  // requested method translated to string
	string			m_strURIRequested;  // requested resource name
	string			m_strLocalFilename;  // constructed local file name
	string			m_strQueryString;  // query string for forms/GET
	string			m_strSvcURI;  // URI of SOAP service for lookup in config data
	string			m_strExtraPath;  // remaining path component after svc URI is removed
	BOOL			m_bHTTPVersionFound;  // request HTTP version found flag
	int				m_nHTTPMajorVersion; // request HTTP version major number
	int				m_nHTTPMinorVersion; // request HTTP version minor number
	string			m_strHTTPVersion; // HTTP protocol version str
	MIMEContentType	m_ContentType; // value of HTTP content-type header
	string			m_strCharsetParam; // value of content-type charset param
    string          m_strSOAPAction; // SOAPAction value

	map<string, string>	m_mapHeaders; // header storage

	DIMEParser		m_DIMEParser; // parser/storage for DIME attachments

    int             m_nSOAPVersion; // SOAP version

	// headers
//	Allow				// RFP 1945 10.1
//	Authorization		// RFP 1945 10.2
//	Content-Encoding	// RFP 1945 10.3
//	Content-Length		// RFP 1945 10.4
//	Content-Type		// RFP 1945 10.5
//	Date				// RFP 1945 10.6
//	Expires				// RFP 1945 10.7
//	From				// RFP 1945 10.8
//	If-Modified-Since	// RFP 1945 10.9
//	Last-Modified		// RFP 1945 10.10
//	Location			// RFP 1945 10.11
//	Pragma				// RFP 1945 10.12
//	Referer				// RFP 1945 10.13
//	Server				// RFP 1945 10.14
//	User-Agent			// RFP 1945 10.15
//	WWW-Authenticate	// RFP 1945 10.16
//	Accept				// RFP 1945 D.2.1
//	Accept-Charset		// RFP 1945 D.2.2
//	Accept-Encoding		// RFP 1945 D.2.3
//	Accept-Language		// RFP 1945 D.2.4
//	Content-Language	// RFP 1945 D.2.5
//	Link				// RFP 1945 D.2.6
//	MIME-Version		// RFP 1945 D.2.7
//	RetryAfter			// RFP 1945 D.2.8
//	Title				// RFP 1945 D.2.9
//	URI					// RFP 1945 D.2.10

	// alternative to "strtok()" for multi-threading app
	char *m_pszStart;
	char *GetToken(char *szString, char *pszDelimiters);
};

#define ST_READ_HDR 10
#define ST_READ_BODY 11
#define ST_PROCESS_SIMPLE 12
#define ST_PROCESS_FULL 13
#define ST_NETWORK_ERROR 14
#define ST_PROTO_ERROR 15
#define ST_INTERNAL_ERROR 16
#define ST_SENDING 17
#define ST_DATA_SENT 18
#define ST_TERMINAL 19

// socket events
#define EV_SOCK_CLOSE 10
#define EV_SOCK_IO_COMPLETION 11
// header parsing events
#define EV_SIMPLE_REQUEST 20
#define EV_FULL_REQUEST 21
#define EV_ENTITYBODY_PENDING 22
#define EV_PROCESS_REQUEST 23
// protocol error handling
#define EV_ERROR_HANDLED 30
#define EV_REQUEST_ERROR 31
#define EV_METHOD_ERROR 32
#define EV_HTTP_VERSION_ERROR 33
//#define EV_UNAUTHORIZED_ERROR 34
#define EV_NOT_FOUND_ERROR 35
#define EV_NOT_AVAILABLE_ERROR 36
#define EV_FORBIDDEN_ERROR 37
// read entity body event
#define EV_BODY_COMPLETE 40
// processing events
#define EV_PROCESSING_DONE 50
#define EV_DATA_SENT 51
// internal error handling
#define EV_PROCESSING_ERROR 60
// terminal event
#define EV_TERMINATE 70

#define TR_READ_HDR_TO_READ_HDR 10
#define TR_READ_HDR_TO_PROC_SIMPLE 11
#define TR_READ_HDR_TO_REQ_ERROR 12
#define TR_READ_HDR_TO_PROC_FULL 13
#define TR_READ_HDR_TO_NET_ERROR 14

#define TR_PROC_SIMPLE_TO_REQ_ERROR 20
#define TR_PROC_SIMPLE_TO_HTTP_VER_ERROR 21

#define TR_PROC_FULL_TO_METHOD_ERROR 40
#define TR_PROC_FULL_TO_REQ_ERROR 41
#define TR_PROC_FULL_TO_NOTFOUND_ERROR 42
#define TR_PROC_FULL_TO_NOTAVAILABLE_ERROR 43
#define TR_PROC_FULL_TO_FORBIDDEN_ERROR 44
#define TR_PROC_FULL_TO_HTTP_VER_ERROR 45
#define TR_PROC_FULL_TO_INTERNAL_ERROR 46
#define TR_PROC_FULL_TO_NET_ERROR 47

#define TR_PROC_FULL_TO_PROC_FULL 50
#define TR_PROC_FULL_TO_SENDING 51
#define TR_PROC_FULL_TO_READ_BODY 52

#define TR_READ_BODY_TO_READ_BODY 60
#define TR_READ_BODY_TO_PROC_FULL 61
#define TR_READ_BODY_TO_NET_ERROR 62

#define TR_PROTO_ERROR_TO_SENDING 81
#define TR_INTERNAL_ERROR_TO_SENDING 82

#define TR_SENDING_TO_SENDING 90
#define TR_SENDING_TO_DATA_SENT 91
#define TR_SENDING_TO_NET_ERROR 92

#define TR_DATA_SENT_TO_TERM 95
#define TR_NET_ERROR_TO_TERM 96

// internal errors
#define ERR_NO_ERROR 0


#endif // !defined(AFX_WMSOAPCLIENTCONN_H__CC9DCCCB_876B_47FF_A8C1_88DC96EFE044__INCLUDED_)
