/* Web Polygraph       http://www.web-polygraph.org/
 * (C) 2003-2006 The Measurement Factory
 * Licensed under the Apache License, Version 2.0 */

#ifndef POLYGRAPH__RUNTIME_HTTPHDRS_H
#define POLYGRAPH__RUNTIME_HTTPHDRS_H

#include "xstd/h/iostream.h"

#include "xstd/Array.h"
#include "xstd/NetAddr.h"
#include "xstd/Checksum.h"
#include "base/ObjId.h"
#include "runtime/ObjWorld.h"
#include "runtime/XactAbortCoord.h"
#include "runtime/HttpVersion.h"


class MsgHdrParsTab;
class HttpCookies;

class HttpUri {
	public:
		HttpUri(): pathBuf(0), pathLen(-1) {}

	public:
		ObjId oid;
		NetAddr host;
		const char *pathBuf;
		int pathLen;
};

// common interface for parsing HTTP requests and responses
class MsgHdr {
	public:
		typedef bool (MsgHdr::*Parser)(const char *buf, const char *eoh);

	protected:
		static bool ParseHostInUri(const char *&start, const char *eorl, NetAddr &host);

	public:
		MsgHdr(const MsgHdrParsTab &aTab);
		virtual ~MsgHdr() {}

		virtual void reset();

		bool persistentConnection() const;
		bool knownContentType() const;
		bool markupContent() const;
		bool chunkedEncoding() const;

		bool parse(const char *buf, Size sz);
		bool parseUri(const char *&buf, const char *eoh, HttpUri &uri);

		virtual void store(OLog &log) const;

	protected:
		static void Configure(MsgHdrParsTab &tab);
		static int AddParser(const String &field, Parser parser, MsgHdrParsTab &tab);

	protected:
		void parseFields();
		bool parseUniqId(const char *&buf, const char *eoh, UniqId &id);
		bool parseWorld(const char *buf, const char *eoh, ObjWorld &world);

		virtual bool parseRLine(const char *buf, const char *eol) = 0;

	public:
		// can be used by both requests and replies
		bool parseHttpVersion(const char *&beg, const char *end, HttpVersion &v);
		bool parseDate(const char *buf, const char *eoh);
		bool parseContLen(const char *buf, const char *eoh);
		bool parseContMd5(const char *buf, const char *eoh);
		bool parseContType(const char *buf, const char *eoh);
		bool parsePragma(const char *buf, const char *eoh);
		bool parseCControl(const char *buf, const char *eoh);
		bool parseXXact(const char *buf, const char *eoh);
		bool parseXTarget(const char *buf, const char *eoh);
		bool parseXRemWorld(const char *buf, const char *eoh);
		bool parseXAbort(const char *buf, const char *eoh);
		bool parseXPhaseSyncPos(const char *buf, const char *eoh);
		bool parseConnection(const char *buf, const char *eoh);
		bool parseTransferEncoding(const char *buf, const char *eoh);

		// these have to be here so we can register them in req
		virtual bool parseGetReqLine(const char *buf, const char *eorl);
		virtual bool parseHeadReqLine(const char *buf, const char *eorl);
		virtual bool parsePostReqLine(const char *buf, const char *eorl);
		virtual bool parsePutReqLine(const char *buf, const char *eorl);
		virtual bool parseHost(const char *buf, const char *eoh);
		virtual bool parseIms(const char *buf, const char *eoh);
		virtual bool parseXLocWorld(const char *buf, const char *eoh);
		virtual bool parseAcceptEncoding(const char *buf, const char *eoh);
		

		// these have to be here so we can register them in rep
		virtual bool parseServer(const char *buf, const char *eoh);
		virtual bool parseLocation(const char *buf, const char *eoh);
		virtual bool parseLMT(const char *buf, const char *eoh);
		virtual bool parseExpires(const char *buf, const char *eoh);
		virtual bool parseCookie(const char *buf, const char *eoh);

	public:
		const MsgHdrParsTab &theParsTab;

		Size theHdrSize;
		HttpVersion theHttpVersion;
		Time theDate;          // Date: header field
		Size theContSize;
		Checksum theChecksum;  // Content-MD5

		UniqId theGroupId;
		UniqId theXactId;
		NetAddr theTarget;

		ObjWorld theRemWorld; // remote object world specs
		XactAbortCoord theAbortCoord; // abort coordinates
		int thePhaseSyncPos; // index of a ready-to-stop phase

		enum { kaNo, kaDefault, kaYes } theConnectionKeepAlive;
		enum { ctUnknown, ctMarkup, ctOther } theContType; // content type
		enum { tcNone, tcChunked, tcIdentity, tcOther } theTransferEncoding;
		bool isCachable;

	protected:
		Array<const char *> theFields; // positions of header fields
		const char *theBufBeg, *theBufEnd;
		const char *theSrchPtr;        // parse buffer iterator
		enum { ssFirst, ssSkip, ssFound } theSrchState;
};

class ReqHdr: public MsgHdr {
	public:
		static void Configure();
		static void Clean();
		
	public:
		ReqHdr();

		virtual void reset();

		virtual void store(OLog &log) const;

		bool expectBody() const;
		bool acceptedEncoding(int coding) const;

	protected:
		virtual bool parseRLine(const char *buf, const char *eol);

		bool parseAnyReqLine(const char *buf, const char *eorl);

		virtual bool parseAcceptEncoding(const char *buf, const char *eoh);
		virtual bool parseGetReqLine(const char *buf, const char *eorl);
		virtual bool parseHeadReqLine(const char *buf, const char *eorl);
		virtual bool parsePostReqLine(const char *buf, const char *eorl);
		virtual bool parsePutReqLine(const char *buf, const char *eorl);
		virtual bool parseHost(const char *buf, const char *eoh);
		virtual bool parseIms(const char *buf, const char *eoh);
		virtual bool parseXLocWorld(const char *buf, const char *eoh);

	protected:
		static MsgHdrParsTab *TheParsTab;

	public:
		HttpUri theUri;
		Time theIms;          // If-Modified-Since timestamp
		ObjWorld theLocWorld; // local world info
		bool isHealthCheck;
		bool isAcceptingGzip;
};

class RepHdr: public MsgHdr {
	public:
		enum StatusCode { scUnknown = -1, sc200_OK = 200, 
			sc204_NoContent = 204,
			sc300_Choices = 300, sc302_Found = 302, sc303_Other = 303,
			sc304_NotModified = 304, sc307_TmpRedir = 307,
			sc403_Forbidden = 403,
			sc406_NotAcceptable = 406,
			sc407_ProxyAuthRequired = 407 };

		static bool PositiveStatusCode(int code);

	public:
		static void Configure();
		static void Clean();
		
	public:
		RepHdr();

		virtual void reset();

		bool polyHeaders() const { return theXactId || theTarget; }
		bool expectPolyHeaders() const;
		bool expectBody() const;

		bool redirect() const;

		Time calcLmt() const;

		virtual void store(OLog &log) const;

		void collectCookies(HttpCookies *cookies);

		bool acceptedEncoding(int coding) const;

	protected:
		virtual bool parseRLine(const char *buf, const char *eol);

		virtual bool parseServer(const char *buf, const char *eoh);
		virtual bool parseLocation(const char *buf, const char *eoh);
		virtual bool parseLMT(const char *buf, const char *eoh);
		virtual bool parseExpires(const char *buf, const char *eoh);
		virtual bool parseCookie(const char *buf, const char *eoh);

	protected:
		static MsgHdrParsTab *TheParsTab;

	public:
		HttpUri theLocn;  // Location: in 3xx responses
		Time theLMT;      // Last-Modified-Time header field
		Time theExpires;  // Expires HTTP header field
		int theStatus;    // HTTP status code

		String theServer; // server agent string
		HttpCookies *theCookies; // a place to collect cookies, if needed
};

inline ostream &crlf(ostream &os) { return os.write("\r\n", 2); }

#endif


syntax highlighted by Code2HTML, v. 0.9.1