// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1995
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        httpresponse.h
// 
// Purpose:     
// 
// Created:     22 Feb 96   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// $Id: httpresponse.h,v 1.10 1996/10/24 09:18:19 jfasch Exp $
// 
// $Log: httpresponse.h,v $
// Revision 1.10  1996/10/24 09:18:19  jfasch
// verbose.h and assert.h and new.h, ERROR was a macro under NT
//
// Revision 1.9  1996/05/23 14:54:23  tvollmer
// removed old tmpfield
//
// Revision 1.8  1996/04/23 13:26:26  tvollmer
// added setHdr()
//
// Revision 1.7  1996/04/11 10:12:48  jfasch
// added version control
//
// Revision 1.6  1996/03/07 10:16:07  jfasch
// changed return value of setXxx() from void to be HTTPResponse& (i.e.,
// *this)
//
// Revision 1.5  1996/03/04 08:49:08  jfasch
// - made HTTPResponse RefCounted
// - added HTTPResponsePtr (SmartPtr)
//
// Revision 1.4  1996/03/04 08:41:33  tvollmer
// *** empty log message ***
//
// Revision 1.3  1996/02/28 12:31:17  jfasch
// intermediary
//
// Revision 1.2  1996/02/27 10:32:11  jfasch
// moved to common/http library
//
// Revision 1.1  1996/02/22 17:12:05  jfasch
// Initial revision
//
// 
// </file> 
#ifndef hg_http_httpresponse_h
#define hg_http_httpresponse_h

#include "libhttp.h"

#include "httphdr.h"

class RString ;

// <class>
//  
// Name:             HTTPResponse
// 
// Purpose:          incremental parsing of HTTP responses as defined in the spec
// 
// Public Interface: yes
// 
// Description:      
// 
// you may add characters that you read from a connection until the
// HTTPResponse is complete or encounters a syntax error. eats up the status
// line, the following header fields, and the terminating CRLF
// empty line.
// 
// add chars by calling either of the below add() methods :-)
//
// when consuming chars, this may take correcting action such as
// eliminating unnecessary white spaces and inserting missing CRs just
// for fun. so the resulting length of the response may differ from
// the number of characters you have read from your connection.
// 
// </class> 
class HTTPResponse : public RefCounted {
public:
   enum {
     INIT,
     H,
     T1,
     T2,
     P,
     SLASH,
     VER,
     WS1,
     C1,
     C2,
     C3,
     WS2,
     REASON,
     CR,
     HDR,
     TERM,
     HTTPERROR,
     VER09
   } ;
   
public:
   HTTPResponse() ;
   HTTPResponse(const RString&, const RString&, const RString&);
   HTTPResponse (const HTTPResponse&) ;
   ~HTTPResponse() ;

   HTTPResponse& operator = (const HTTPResponse&) ;


   // 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.
   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) ;

   // same semantics as in HTTPHeader
   bool ok() const { return state_!=HTTPERROR; }
   bool complete() const { return state_==TERM; }

   // these, of course, are only meaningful when complete()
   const RString& version() const { return version_; }
   const RString& code() const { return code_; }
   const RString& reason() const { return reason_; }

   HTTPResponse& setVersion(const RString& it) { version_=it; return *this; }
   HTTPResponse& setCode(const RString& it) { code_=it; return *this; }
   HTTPResponse& setReason(const RString& it) { reason_=it; return *this; }

   // in addition to a status line, the response most probably will
   // contain some header fields. see there for further explanation
   // about the extraction of the fields.
   const HTTPHeader& hdr() const { return hdr_; }
   HTTPHeader& getHdr() { return hdr_; }
    void setHdr(const HTTPHeader& it) {hdr_=it;}

   int length(const RString& =" ",const RString& = " ",const RString& ="\r\n",
              const RString& =": ",const RString& ="\r\n", const RString& ="\r\n") const;
   int write(char *,const RString& =" ",const RString& = " ",const RString& ="\r\n",
             const RString& =": ",const RString& ="\r\n", const RString& ="\r\n" ) const;
   RString all(const RString& =" ",const RString& = " ",const RString& ="\r\n",
               const RString& =": ",const RString& ="\r\n", const RString& ="\r\n") const;

private:
   RString version_ ;
   RString code_ ;
   RString reason_ ;

   HTTPHeader hdr_ ;            // the header lines (see there for parsing/getting fields)

   int state_ ;

   class TmpField* tmp_ ;

public:
   static const char* version2 ;
} ;
static const char* hg_http_httpresponse_version = HTTPResponse::version2 ;

SmartPtrdeclare (HTTPResponsePtr, HTTPResponse) ;


#endif
