/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


#ifndef DDWEBREQUEST_H
#define DDWEBREQUEST_H

#include <ddiourl.h>
#include <ddstringrow.h>
#include <ddbasetime.h>
#include <ddwebcookie.h>


using namespace std;

class ddwebxrequest_old;
class ddwebresponse;
class ddcreator;
class ddiobuffer;



typedef map<ddstring, ddwebcookie> ddwebcookiemap;


/// ddwebrequest: Ein HTTP request.
/**
	ddwebrequest	ist eine ddstringrow, die alle Daten 
	eines HTTP Requests enthält.
*/

class ddwebrequest : public ddstringrow
{

public:

	enum dd_reqtypes
	{
		req_none = 0,
		req_get,
		req_post,
		req_head,

		dd_reqtypes_size
	};


	enum dd_reqspecialtypes
	{
		req_content_length = -1,
		req_cookie = -2,
		req_keep_alive = -3
	};
	
	enum dd_reqfields
	{
		req_host=0,							// 0
		req_port,								// 1
		req_hostport,						// 2
		req_domain,							// 3
		req_user_agent,					// 4
		req_referer,						// 5
		req_content_type,				// 6
    req_if_modified_since,	// 7
    req_raw_path,						// 8
  	req_cgi_path,						// 9
		req_raw_path_esc,				// 10
		req_post_content,				// 11
		req_full_path,					// 12
		
		req_fields_size
	};

	ddwebrequest();
	virtual ~ddwebrequest();


  /**
  	Gibt 'true' zurück, wenn das Keep-Alive Flag gesetzt ist.
  */

  inline bool is_keep_alive() const
  {
  	return _keepalive;
  }


	/**
  	Gibt 'true' zurück, wenn daten hochgeladen werden.
  */

  inline bool is_upload() const
  {
  	return _upload;
  }
	
	
	/**
  	Gibt 'true' zurück, wenn der request ein interner redirect ist,
  	d.h. wenn der pfad von /vista_ist_doof.html auf /faqsthread/1234
  	umgebogen wurde. Getestet wird das über die pfad und splitpath
  */

  inline bool is_internal_redirect()
  {
  	// splitpath[0], also vermutlich 'faqsthread', wird nicht im original
  	// pfad gefunden, also ist das ein interner redirect.
  	return ( !get_full_path().contains( get_split_path()[0] ) );
  }
	
	
	/**
  	Gibt den Request-Typ-Namen zurück: "GET", "POST", "HEAD"
  */

  inline ddstring get_request_type_name() const
  {
  	return ddstring( dd_reqtype[_requesttype] );
  }

	/**
  	Gibt die Request-Typ zurück: GET, POST, HEAD
  */

  inline int get_request_type() const
  {
  	return _requesttype;
  }
	
  /**
  	Gibt die lokale Umsetzung (=URL) des Requests zurück.
  	Wird erst ddwebsite umgesetzt.
  	@see ddrequrl
  */
	
  inline ddiourl& get_local_url()
  {
  	return _url;
  }


  /**
  	Gibt die CGI-Daten  zurück.
   	@see ddwebcgi
  */

  inline ddwebcgi& get_cgi()
  {
  	return _cgi;
  }


  /**
  	Gibt den Port zurück.
  */

  inline ddstring& get_port()
  {
  	return (*this)[ddwebrequest::req_port];
  }


  /**
  	Gibt den Hostnamen zurück.
  */

  inline ddstring& get_host_name()
  {
  	return (*this)[ddwebrequest::req_host];
  }

  
  /**
  	Gibt den Hostname mit Port zurück.
  */

  inline ddstring& get_host_port()
  {
  	return (*this)[ddwebrequest::req_hostport];
  }


  /**
  	Gibt den Domainname zurück, also
  	'zonc.net' für 'shizzo.zonc.net'
  */

  inline ddstring& get_domain_name()
  {
  	return (*this)[ddwebrequest::req_domain];
  }
  

  /**
  	Gibt den 'User-Agent' zurück.
  */

  inline ddstring& get_user_agent()
  {
  	return (*this)[ddwebrequest::req_user_agent];
  }


  /**
  	Gibt den Referer zurück.
  */

  inline ddstring& get_referer()
  {
  	return (*this)[ddwebrequest::req_referer];
  }
  

  /**
  	Gibt das Cookie mit dem angegebenen Namen zurück.
  */

  inline ddwebcookie& get_cookie( const ddstring& key )
  {
  	return _cookies[ key ];
  }


  /**
  	Gibt den "Content type" Eintrag der Post-Daten zurück.
  */

  inline ddstring& get_content_type()
  {
  	return (*this)[ddwebrequest::req_content_type];
  }

  /**
  	Gibt den "modified since" Eintrag der Daten zurück.
  */

  inline ddstring& get_if_modified_since()
  {
  	return (*this)[ddwebrequest::req_if_modified_since];
  }


  /**
  	Gibt die Länge der Post-Daten zurück.
  */

  inline int get_content_length()
  {
  	return _contentlength;
  }


  /**
  	@return den requestbody (POST data)
  */

  inline ddstring& get_post_content()
  {
  	return (*this)[ddwebrequest::req_post_content];
  }

 
  /**
  	@return den Gesamtpfad inclusive CGI
  */

  inline const ddstring& get_raw_path() const
  {
  	return (*this)[ddwebrequest::req_raw_path];
  }
 
 
  /**
  	@return den Gesamtpfad ohne CGI
  */

  inline ddstring& get_full_path()
  {
  	return (*this)[ddwebrequest::req_full_path];
  }
 
 
  /**
  	@return Den Gesamtpfad inclusive CGI in 'escaped-er' form,
  	um ihn seinerseits in ein CGI-Feld zu stopfen.
  */
	
	ddstring get_raw_path_escaped(); 	
	
	
	/**
  	@return den CGI-Datenblock
  */

  inline ddstring& get_cgi_path()
  {
  	return (*this)[ddwebrequest::req_cgi_path];
  }

  
  /**
  	@return den Pfad zerhäckselt, also /home/ernie/pics/bert.gif as "home" "ernie" "pics" "bert.gif"
  	@see get_fullpath
  */

  inline ddstringrow& get_split_path()
  {
  	return _splitpath;
  }
			
  
  bool has_cookie( const ddstring& key );
 	//??
 	void set_raw_path( const ddstring& path );
	
  int  parse( const char* data, size_t len, ddstring& error );  
	int  parse_post( const char* data, size_t len ); 
  int  parse_upload( const char* data, size_t len ); 
 	int  parse_path( ddstring& path );  
	
	void clear(); 
	void dump() const;	

protected:

  // ex parser:
  void parse_init();
  int  parse_header();
  int  parse_fields();  
 	void parse_upload_block( const char* data, size_t len ); 
  int  parse_cookies( const ddstring& rawcookies );
  
  int  parse_error( const ddstring& error );
  
  int  check_path( const ddstring& path );  
	
  int 			  		_protminor;
  int				  		_requesttype;
  int 						_contentlength;
  bool			  		_keepalive;
	bool						_upload;
  
  ddstring*	  		_error;
  ddstringrow	  	_splitpath;
  ddwebcookiemap 	_cookies;

	ddiourl	    		_url;
	ddwebcgi				_cgi;

  // ex parser:
  ddstringrow   	_lines;
 	ddmapindex			_fieldindex;

private:
	
	static const char* dd_reqtype[];
	
	ddwebrequest( const ddwebrequest& src )
	{
	}
	ddwebrequest& operator=( const ddwebrequest& src )
	{
		return *this;
	}

};


/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/



using namespace std;



class ddwebxrequest_old;
class ddwebresponse;
class ddcreator;
class ddiobuffer;


typedef map<ddstring, ddwebcookie> ddwebcookiemap;

/// ddwebresponse: eine http response .
/**
	ddwebresponse: eine http response.
*/


class ddwebresponse : public ddstringrow
{

public:

  enum dd_header_fields
	{
		header_retcode=1,
		header_server=3,
    header_date=5,
		header_set_cookie=7,
		header_content_type=9,
		header_content_length=11,
    header_last_modified=13,
    header_location=15,
		
		header_expires=17,
		header_cache_control1=19,
		header_cache_control2=21,		
		header_pragma=23,
		
		header_fields_size=24
	};

	enum dd_header_retcode
	{	
		/*
		ret_100_http_continue                     = 100
		ret_101_switching_protocols          = 101
		ret_102_processing                   = 102
		*/
		ret_200_ok = 0,
		ret_201_created,
		ret_202_accepted,
		ret_203_non_authoritative,
		ret_204_no_content,
		ret_205_reset_content,
		ret_206_partial_content,
		ret_207_multi_status,
		ret_300_multiple_choices,
		ret_301_moved_permanently,
		ret_302_moved_temporarily,
		ret_303_see_other,
		ret_304_not_modified,
		ret_305_use_proxy,
		ret_307_temporary_redirect,
		ret_400_bad_request,
		ret_401_unauthorized,
		ret_402_payment_required,
		ret_403_forbidden,
		ret_404_not_found,
		ret_405_method_not_allowed,
		ret_406_not_acceptable,
		ret_407_proxy_authentication_required,
		ret_408_request_time_out,
		ret_409_conflict,
		ret_410_gone,
		ret_411_length_required,
		ret_412_precondition_failed,
		ret_413_request_entity_too_large,
		ret_414_request_uri_too_large,
		ret_415_unsupported_media_type,
		ret_416_range_not_satisfiable,
		ret_417_expectation_failed,
		ret_422_unprocessable_entity,
		ret_423_locked,
		ret_424_failed_dependency,
		ret_500_internal_server_error,
		ret_501_not_implemented,
		ret_502_bad_gateway,
		ret_503_service_unavailable,
		ret_504_gateway_time_out,
		ret_505_version_not_supported,
		ret_506_variant_also_varies,
		ret_507_insufficient_storage,
		ret_510_not_extended,
		ret_code_size
	};


	ddwebresponse();
	virtual ~ddwebresponse();
	
	void 			init_data();
	void      set_retcode( size_t msg );
  ddstring  create_retcode( size_t msg );
	
	void 			flush_data( ddiobuffer& buffer );
	ddstring  to_string() const;
	void      dump( const ddstring& type ) const;
	
	inline void set_content_length( size_t length )
	{
		(*this)[ddwebresponse::header_content_length].from_size_t( length );
	}
	
	
	inline ddwebcookie& get_cookie()
	{
		return _cookie;
	}
	
	
	inline ddstring& get_server_id()		
	{
		return (*this)[ddwebresponse::header_server];
	}
	
	
	inline ddstring& get_content_type()		
	{
		return (*this)[ddwebresponse::header_content_type];
	}
	
	
	inline const ddstring& get_retcode()		
	{
		return (*this)[ddwebresponse::header_retcode];
	}
	
	
	inline ddstring get_retcode_short()		
	{
		return ddstring( dd_ret_msg_short[_retcode] );
	}
	
	
	inline ddstring create_retcode_short( size_t retcode )		
	{
		return ddstring( dd_ret_msg_short[retcode] );
	}
	
	
	inline ddstring& get_content_length()		
	{
		return (*this)[ddwebresponse::header_content_length];
	}
	
	
	inline void set_date( time_t date )		
	{
		_date = date;
		(*this)[ddwebresponse::header_date] = get_date().to_string_gmt();
	}
	
	
	inline ddbasedate get_date()		
	{
		return ddbasedate( _date );
	}
	
	
	inline const ddstring& get_date_string()		
	{
		return (*this)[ddwebresponse::header_date];
	}
	
	
	inline ddstring& get_last_modified()		
	{
		return (*this)[ddwebresponse::header_last_modified]; 
	}
	
	
	inline ddstring& get_location()	
	{
		return (*this)[ddwebresponse::header_location]; 
	}

	
	void set_allow_caching( bool usecache );
	
	
protected:

	static const char* dd_header[];
	static const char* dd_ret_msg[];
	static const char* dd_ret_msg_short[];
	
	size_t		_retcode;
	time_t		_date;
	
	ddwebcookie  _cookie;
	
private:

	ddwebresponse( const ddwebresponse& src );
	ddwebresponse& operator=( const ddwebresponse& src );

};





#endif

