// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1994
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        httphdr.h
// 
// Purpose:     
// 
// Created:     2 Oct 95   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// $Id: httphdr.h,v 1.24 1997/02/03 14:34:33 tvollmer Exp $
//
// $Log: httphdr.h,v $
// Revision 1.24  1997/02/03 14:34:33  tvollmer
// added status for cgi responses
//
// Revision 1.23  1997/02/03 14:31:32  tvollmer
// added status for cgi responses
//
// Revision 1.22  1997/02/03 14:26:16  jfasch
// shortcut for finished entry
//
// Revision 1.21  1996/10/24 09:18:19  jfasch
// verbose.h and assert.h and new.h, ERROR was a macro under NT
//
// Revision 1.20  1996/07/24 06:25:42  jfasch
// added RString constants for header fields
//
// Revision 1.19  1996/07/18 13:28:57  tvollmer
// added cache-control
//
// Revision 1.18  1996/07/15 12:11:44  jfasch
// changed Header to HttpHeader
//
// Revision 1.17  1996/06/14 11:36:15  tvollmer
// added host
//
// Revision 1.16  1996/06/12 14:57:46  jfasch
// some comment for add (const char*, int)
//
// Revision 1.15  1996/04/24 12:01:37  tvollmer
// added authorization
//
// Revision 1.14  1996/04/18 10:23:44  jfasch
// removed some code in comments
//
// Revision 1.13  1996/04/11 10:12:48  jfasch
// added version control
//
// Revision 1.12  1996/03/07 10:09:53  jfasch
// changed return value of all set- and add-operations from void to HTTPHeader&
//
// Revision 1.11  1996/03/06 12:59:26  tvollmer
// set-cookie
//
// Revision 1.10  1996/03/04 08:50:10  jfasch
// - made Header RefCounted
// - added HTTPHeaderPtr (SmartPtr)
//
// Revision 1.9  1996/03/04 08:41:33  tvollmer
// *** empty log message ***
//
// Revision 1.8  1996/02/28 12:31:17  jfasch
// intermediary
//
// Revision 1.7  1996/02/27 10:32:11  jfasch
// moved to common/http library
//
// Revision 1.6  1996/02/22 17:11:27  jfasch
// comments, comments ...
//
// Revision 1.5  1996/02/22 16:47:42  jfasch
// added bool contentEncoding (RString& v) const
//
// Revision 1.4  1996/02/19 19:27:58  jfasch
// - changed include libutils.h to libcommon.h
//
// Revision 1.3  1996/02/19 15:17:13  jfasch
// - replaced state TAG by state NAME
//
// Revision 1.2  1996/02/19 15:11:56  jfasch
// - parse during adding so that extracting field will always be correct later on
//
// 
// </file> 
#ifndef hg_http_httphdr_h
#define hg_http_httphdr_h

#include "libhttp.h"

#include "hdrfields.h"

#include <hyperg/utils/smartptr.h>

class RString ;

// <class>
//  
// Name:             HttpHeader
// 
// Purpose:          incremental parsing of HTTP header lines as defined in the spec
// 
// Public Interface: yes
// 
// Description:      
// 
// you may add characters that you read from a connection until the
// Header is complete or encounters a syntax error. eats up every
// line of your header lines, including the terminating CRLF empty
// line.
//
// the header fields are stored in a HeaderFields object (see there
// fur further description).
// 
// add chars by calling either of the below add() methods :-)
//
// </class> 
class HttpHeader : public RefCounted {
public:
   enum {
     INIT,
     NAME,
     WS1,
     COL,
     WS2,
     VAL,
     CR,
     LF,
     CRTERM,
     TERM,
     HTTPERROR
   } ;
public:
   HttpHeader() ;
   HttpHeader (const HttpHeader&) ;
   ~HttpHeader() ;

   HttpHeader& operator = (const HttpHeader&) ;

   bool ok() const { return state_!=HTTPERROR; }
   bool complete() const { return state_==TERM; }

   const HeaderFields& lines() const { return lines_; }
   HeaderFields& getLines() { return lines_; }

   // returns number of characters sucessfully accepted. these will
   // then be part of the header data. nevertheless, you have to check
   // the state of this afterwards to determine if
   // ready/error/wantmore.
   // NOTE: even if there was an error the number of successfully
   // accepted chars is returned (up to, but not including, the
   // erroneous one). this enables you to determine where the error
   // occured.
   int add (const char*, int) ;

   // false if error (this not ok() anymore). true if the char was
   // accepted; i.e., added to my data. if true, my state may be
   // "complete" or "no error and want more"; user has to check this
   // afterwards.
   bool add (char) ;

private:
   // just a tool to flush the current header line out to the lines_.
   bool flush_hdr_() ;

private:
   HeaderFields lines_ ;
   int state_ ;

   class TmpField* tmp_ ;

public:
   static const char* version1 ;
} ;
static const char* hg_http_header_version = HttpHeader::version1 ;

class HTTPHeader:public HttpHeader
{
public:
// this is sorted alpabetically !!
   static const RString rsAuthorization ;
   const RString& authorization() const { return lines().value(rsAuthorization);}
   HTTPHeader& addAuthorization(const RString& it) ;
   HTTPHeader& setAuthorization(const RString& it) ;

   static const RString rsCacheControl ;
   const RString& cacheControl() const { return lines().value(rsCacheControl);}
   HTTPHeader& addCacheControl(const RString& it) ;
   HTTPHeader& setCacheControl(const RString& it) ;

   static const RString rsConnection ;
   const RString& connection() const { return lines().value(rsConnection);}
   HTTPHeader& addConnection(const RString& it) ;
   HTTPHeader& setConnection(const RString& it) ;

   static const RString rsContentEncoding ;
   const RString& contentEncoding() const { return lines().value(rsContentEncoding);}
   HTTPHeader& addContentEncoding(const RString& it) ;
   HTTPHeader& setContentEncoding(const RString& it) ;

   static const RString rsContentLength ;
   const RString& contentLength() const { return lines().value(rsContentLength);}
   HTTPHeader& addContentLength(const RString& it) ;
   HTTPHeader& setContentLength(const RString& it) ;

   static const RString rsContentType ;
   const RString& contentType() const { return lines().value(rsContentType);}
   HTTPHeader& addContentType(const RString& it) ;
   HTTPHeader& setContentType(const RString& it) ;

   static const RString rsCookie ;
   const RString& cookie() const { return lines().value(rsCookie);}
   HTTPHeader& addCookie(const RString& it) ;
   HTTPHeader& setCookie(const RString& it) ;

   static const RString rsDate ;
   const RString& date() const { return lines().value(rsDate);}
   HTTPHeader& addDate(const RString& it) ;
   HTTPHeader& setDate(const RString& it) ;

   static const RString rsExpires ;
   const RString& expires() const { return lines().value(rsExpires);}
   HTTPHeader& addExpires(const RString& it) ;
   HTTPHeader& setExpires(const RString& it) ;

   static const RString rsHost ;
   const RString& host() const { return lines().value(rsHost);}
   HTTPHeader& addHost(const RString& it) ;
   HTTPHeader& setHost(const RString& it) ;

   static const RString rsIfModifiedSince ;
   const RString& ifModifiedSince() const { return lines().value(rsIfModifiedSince);}
   HTTPHeader& addIfModifiedSince(const RString& it) ;
   HTTPHeader& setIfModifiedSince(const RString& it) ;

   static const RString rsLastModified ;
   const RString& lastModified() const { return lines().value(rsLastModified);}
   HTTPHeader& addLastModified(const RString& it) ;
   HTTPHeader& setLastModified(const RString& it) ;

   static const RString rsLocation ;
   const RString& location() const { return lines().value(rsLocation);}
   HTTPHeader& addLocation(const RString& it) ;
   HTTPHeader& setLocation(const RString& it) ;

   static const RString rsMIMEVersion ;
   const RString& mimeVersion() const { return lines().value(rsMIMEVersion);}
   HTTPHeader& addMimeVersion(const RString& it) ;
   HTTPHeader& setMimeVersion(const RString& it) ;

   static const RString rsPragma ;
   const RString& pragma() const { return lines().value(rsPragma);}
   HTTPHeader& addPragma(const RString& it) ;
   HTTPHeader& setPragma(const RString& it) ;

   static const RString rsReferer ;
   const RString& referer() const { return lines().value(rsReferer);}
   HTTPHeader& addReferer(const RString& it) ;
   HTTPHeader& setReferer(const RString& it) ;

   static const RString rsServer ;
   const RString& server() const { return lines().value(rsServer);}
   HTTPHeader& addServer(const RString& it) ;
   HTTPHeader& setServer(const RString& it) ;
    
   static const RString rsStatus ;
   const RString& status() const { return lines().value(rsStatus);}
   HTTPHeader& addStatus(const RString& it) ;
   HTTPHeader& setStatus(const RString& it) ;
   // strange names for setcookie sinc setCookie is set cookie :-)

   static const RString rsSetCookie ;
   const RString& cookieSet() const { return lines().value(rsSetCookie);}
   HTTPHeader& addCookieSet(const RString& it) ;
   HTTPHeader& setCookieSet(const RString& it) ;

   static const RString rsUserAgent ;
   const RString& userAgent() const { return lines().value(rsUserAgent);}
   HTTPHeader& addUserAgent(const RString& it) ;
   HTTPHeader& setUserAgent(const RString& it) ;

   static const RString rsWarning ;
   const RString& warning() const { return lines().value (rsWarning); }
   HTTPHeader& addWarning (const RString&) ;
   HTTPHeader& setWarning (const RString&) ;

   static const RString rsWWWAuthenticate ;
   const RString& wwwAuthenticate() const { return lines().value(rsWWWAuthenticate);}
   HTTPHeader& addWWWAuthenticate(const RString& it) ;
   HTTPHeader& setWWWAuthenticate(const RString& it) ;
};

inline HTTPHeader& HTTPHeader :: addAuthorization (const RString& it) { 
   getLines().insert(rsAuthorization,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setAuthorization (const RString& it) {
   getLines().override(rsAuthorization,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addCacheControl (const RString& it) { 
   getLines().insert(rsCacheControl,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setCacheControl (const RString& it) {
   getLines().override(rsCacheControl,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addConnection (const RString& it) { 
   getLines().insert(rsConnection,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setConnection (const RString& it) {
   getLines().override(rsConnection,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addContentEncoding (const RString& it) {
   getLines().insert(rsContentEncoding,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setContentEncoding (const RString& it) {
   getLines().override(rsContentEncoding,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addContentLength (const RString& it) {
   getLines().insert(rsContentLength,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setContentLength (const RString& it) {
   getLines().override(rsContentLength,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addContentType (const RString& it) {
   getLines().insert(rsContentType,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setContentType (const RString& it) {
   getLines().override(rsContentType,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addCookie (const RString& it) {
   getLines().insert(rsCookie,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setCookie (const RString& it) {
   getLines().override(rsCookie,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addDate (const RString& it) {
   getLines().insert(rsDate,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setDate (const RString& it) {
   getLines().override(rsDate,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addExpires (const RString& it) {
   getLines().insert(rsExpires,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setExpires (const RString& it) {
   getLines().override(rsExpires,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addHost (const RString& it) {
   getLines().insert(rsHost,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setHost (const RString& it) {
   getLines().override(rsHost,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addIfModifiedSince (const RString& it) {
   getLines().insert(rsIfModifiedSince,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setIfModifiedSince (const RString& it) {
   getLines().override(rsIfModifiedSince,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addLastModified (const RString& it) {
   getLines().insert(rsLastModified,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setLastModified (const RString& it) {
   getLines().override(rsLastModified,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addLocation (const RString& it) {
   getLines().insert(rsLocation,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setLocation (const RString& it) {
   getLines().override(rsLocation,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addMimeVersion (const RString& it) {
   getLines().insert(rsMIMEVersion,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setMimeVersion (const RString& it) {
   getLines().override(rsMIMEVersion,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addPragma (const RString& it) {
   getLines().insert(rsPragma,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setPragma (const RString& it) {
   getLines().override(rsPragma,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addReferer (const RString& it) {
   getLines().insert(rsReferer,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setReferer (const RString& it) {
   getLines().override(rsReferer,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addServer (const RString& it) {
   getLines().insert(rsServer,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setServer (const RString& it) {
   getLines().override(rsServer,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: addStatus (const RString& it) {
   getLines().insert(rsStatus,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setStatus (const RString& it) {
   getLines().override(rsStatus,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addCookieSet (const RString& it) {
   getLines().insert(rsSetCookie,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setCookieSet (const RString& it) {
   getLines().override(rsSetCookie,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addUserAgent (const RString& it) {
   getLines().insert(rsUserAgent,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setUserAgent (const RString& it) {
   getLines().override(rsUserAgent,it) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addWarning (const RString& w) {
   getLines().insert (rsWarning, w) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setWarning (const RString& w) {
   getLines().override (rsWarning, w) ;
   return *this ;
}

inline HTTPHeader& HTTPHeader :: addWWWAuthenticate (const RString& it) {
   getLines().insert(rsWWWAuthenticate,it) ;
   return *this ;
}
inline HTTPHeader& HTTPHeader :: setWWWAuthenticate (const RString& it) {
   getLines().override(rsWWWAuthenticate,it) ;
   return *this ;
}


SmartPtrdeclare (HTTPHeaderPtr, HTTPHeader) ;

#endif
