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

#ifndef POLYGRAPH__CLIENT_CLTXACT_H
#define POLYGRAPH__CLIENT_CLTXACT_H

#include "xstd/Queue.h"
#include "base/ObjTimes.h"
#include "runtime/IOBuf.h"
#include "runtime/httpHdrs.h"
#include "runtime/Xaction.h"
#include "client/UserCred.h"
#include "client/SingleCxm.h"

class Client;
class PageInfo;
class ServerRep;
class ContentCfg;
class DistrPoint;
class ObjWorld;
class HostCfg;
class MembershipMap;
class BodyParser;
class ParseBuffer;
class RegExGroup;
class RegExMatchee;
class RndDistr;
class HttpCookies;

class CltXact: public Xaction, public QueueItem {
	public:
		CltXact();

		virtual void reset();

		void enqueue();

		// setup and execution
		void page(PageInfo *aPage);
		PageInfo *page();
		CltXactMgr *getPipeline();
		void pipeline(CltXactMgr *aMgr);
		void exec(Client *anOwner, Connection *aConn);

		// called by CltXactMgr
		bool controlledFill(bool &needMore);
		bool controlledMasterWrite(Size &size);
		bool controlledPostWrite(Size &size, bool &needMore);
		void controlledMasterRead();
		void controlledPostRead();
		void controlledAbort();

		virtual void cacheDistrPoint(DistrPoint *) {}
		virtual bool needRetry() const { return doRetry; }
		virtual void noteAbort();

		// called from BodyParsers
		void noteContent(const ParseBuffer &content);
		Error noteEmbedded(ReqHdr &hdr);
		void noteTrailerHeader(const ParseBuffer &hdr);
		void noteEndOfTrailer();

		bool askedPeer() const { return thePeerState != peerUnknown; }
		bool usePeer() const { return thePeerState == peerSome; }
		void usePeer(bool doUse) { thePeerState = doUse ? peerSome : peerNone; }

		const NetAddr &nextHop() const { return theNextHop; }
		NetAddr &nextHopVar() { return theNextHop; }

		const UserCred &credentials() const { return theCred; }
		void noteCredentialsGone(); // called by filters that stripped creds

		void saveRepHeader();
		const IOBuf &savedRepHeader() const { return theSavedRepHeader; }
		CltXact *cause() { return theCause; }
		const CltXact *cause() const { return theCause; }
		void cause(CltXact *aCause) { theCause = aCause; }
		int childCount() const { return theChildCount; }
		void noteChildNew(CltXact *) { theChildCount++; }
		void noteChildGone(CltXact *) { --theChildCount; }

	protected:
		virtual Agent *owner();
		virtual const UniqId &reqId() const;

		void makeReqHeaders();
		void makeConnectReq(ostream &os);
		void makeExplicitReq(ostream &os);
		void finishReqHdrs(ostream &os, bool forceDump);

		Error getHeader();
		Error interpretHeader();
		void getBody();
		void parse();
		void checkOverflow();
		void noteError(const Error &err);
		void authWithProxy(bool needed);
		void redirect();

		virtual void finish(Error err);
		virtual void logStats(OLog &ol) const;

		void makeReqVersion(ostream &os);
		const HostCfg *makeReqHost(ostream &os);
		void makeReqMethod(ostream &os);
		virtual void makeEndToEndHdrs(ostream &os);
		void makeHopByHopHdrs(ostream &os);
		void makeCookies(ostream &os, HttpCookies *cookies);

		virtual void consume(Size size);
		virtual void firstHandSync();

		Error handleEmbedOid(ReqHdr &hdr);
		Error handleForeignEmbedOid(ReqHdr &hdr);

		bool expectMore() const;
		Size unconsumed() const;
		const ObjTimes &olcTimes() const;
		bool validRelOid(const ObjId &oid) const;
		bool cfgAbortedReply() const;

		void checkAcl();
		void checkAclMatch(const RegExGroup *matchGrp, const char *action);
		void buildAclMatchee(RegExMatchee &m) const;
		void explainAclMatch(const RegExMatchee &m, const char *action, const Array<RegExGroup*> &ourMatches) const;
		void dumpMatchingGroupNames(ostream &os, const MembershipMap *map) const;

		void checkFreshness();
		void checkDateSync();
		void updatePubWorld(const ObjWorld &slice);
		Error setStatusCode(int aStatus);
		Error setViserv(const NetAddr &name, ObjId &oid) const;
		BodyParser *selectBodyParser();
		BodyParser *selectContentParser();
		BodyParser *selectMarkupBodyParser();

		RndDistr *seedOidDistr(RndDistr *raw, int globSeed);

	protected:
		Client *theOwner;
		PageInfo *thePage;
		CltXactMgr *theMgr;
		ServerRep *theSrvRep;
		ContentCfg *theContentCfg;
		BodyParser *theBodyParser;
		NetAddr theNextHop;
		RepHdr theRepHdr;
		mutable ObjTimes theOlcTimes; // cached value
		Size theConsumedSize;
		Size theReqBodySize;
		UserCred theCred;
		IOBuf theSavedRepHeader; // to preserve raw response headers if needed
		SingleCxm theSelfMgr;

		CltXact *theCause;    // transaction that caused this transaction
		int theChildCount;    // transaction using us as a cause

		// this is used to check whether the xaction wants to use peers
		enum { peerUnknown = -1, peerNone, peerSome } thePeerState;

		bool doRetry;		// try the same xaction again
};

#endif


syntax highlighted by Code2HTML, v. 0.9.1