HwangKC 2024-05-24 12:23:42 +08:00
parent a386d0c62b
commit 6dd317d14d
135 changed files with 83405 additions and 0 deletions

3
.gitignore vendored 100644
View File

@ -0,0 +1,3 @@
/3rdPartner/frp_0.56.0_linux_arm.tar.gz
/3rdPartner/go1.22.1.linux-armv6l.tar.gz
/appRelease/test.release

View File

@ -0,0 +1,63 @@
/* -*-c++-*- */
/*
* $Id: CgiDefs.h.in,v 1.10 2014/04/23 20:55:03 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _CGIDEFS_H_
#define _CGIDEFS_H_ 1
/*! \file CgiDefs.h
* \brief Platform and operating system specific macro definitions.
*
* Platform and operating system specific macro definitions that deal
* with namespace support and exporting of library functions.
*/
/*
// Include information from configure
#if HAVE_CONFIG_H
# include "config.h"
#endif
*/
/*! \namespace cgicc
* \brief The namespace containing the cgicc library
*
* The namespace containing all classes and functions of the
* GNU cgicc library.
*/
// Win32-specific setup
#ifdef WIN32
// export library symbols
# ifdef CGICC_EXPORTS
# define CGICC_API __declspec(dllexport)
# else
# define CGICC_API __declspec(dllimport)
# endif
# define HOST "Win32"
# define VERSION "3.2.20"
#else
# define CGICC_API
#endif /* WIN32 */
#endif /* ! _CGIDEFS_H_ */

View File

@ -0,0 +1,363 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: CgiEnvironment.cpp,v 1.31 2017/06/22 20:26:35 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include <new>
#include <memory>
#include <stdexcept>
#include <cstdlib>
#include <cctype>
#ifdef WIN32
# include <io.h>
# include <fcntl.h>
# include <stdio.h>
#endif
#include "CgiEnvironment.h"
// ========== Constructor/Destructor
cgicc::CgiEnvironment::CgiEnvironment(CgiInput *input)
{
// Create a local CgiInput object for us to use
// In the vast majority of cases, this will be used
// For FastCGI applications it won't but the performance hit of
// an empty inline constructor is negligible
CgiInput local_input;
if(0 == input)
readEnvironmentVariables(&local_input);
else
readEnvironmentVariables(input);
// On Win32, use binary read to avoid CRLF conversion
#ifdef WIN32
# ifdef __BORLANDC__
setmode(_fileno(stdin), O_BINARY);
# else
_setmode(_fileno(stdin), _O_BINARY);
# endif
#endif
if(stringsAreEqual(fRequestMethod, "post") || stringsAreEqual(fRequestMethod, "put")) {
// Don't use auto_ptr, but vector instead
// Bug reported by shinra@j10n.org
std::vector<char> data(fContentLength);
if(getenv("CGICC_MAX_CONTENTLENGTH")&&getContentLength()>(long unsigned int)atoi(getenv("CGICC_MAX_CONTENTLENGTH")))
{
throw std::runtime_error("Malformed input");
}
else
// If input is 0, use the default implementation of CgiInput
if ( getContentLength() )
{
// If input is 0, use the default implementation of CgiInput
if ( input == 0 )
{
if ( local_input.read( &data[0], getContentLength() ) != getContentLength() )
throw std::runtime_error("I/O error");
}
else
if ( input->read( &data[0], getContentLength() ) != getContentLength() )
throw std::runtime_error("I/O error");
fPostData = std::string( &data[0], getContentLength() );
}
}
fCookies.reserve(10);
parseCookies();
}
cgicc::CgiEnvironment::~CgiEnvironment()
{}
// Overloaded operators
bool
cgicc::CgiEnvironment::operator== (const CgiEnvironment& env) const
{
bool result;
result = fServerPort == env.fServerPort;
result &= fContentLength == env.fContentLength;
result &= fUsingHTTPS == env.fUsingHTTPS;
result &= fServerSoftware == env.fServerSoftware;
result &= fServerName == env.fServerName;
result &= fGatewayInterface == env.fGatewayInterface;
result &= fServerProtocol == env.fServerProtocol;
result &= fRequestMethod == env.fRequestMethod;
result &= fPathInfo == env.fPathInfo;
result &= fPathTranslated == env.fPathTranslated;
result &= fScriptName == env.fScriptName;
result &= fQueryString == env.fQueryString;
result &= fRemoteHost == env.fRemoteHost;
result &= fRemoteAddr == env.fRemoteAddr;
result &= fAuthType == env.fAuthType;
result &= fRemoteUser == env.fRemoteUser;
result &= fRemoteIdent == env.fRemoteIdent;
result &= fContentType == env.fContentType;
result &= fAccept == env.fAccept;
result &= fUserAgent == env.fUserAgent;
result &= fPostData == env.fPostData;
result &= fRedirectRequest == env.fRedirectRequest;
result &= fRedirectURL == env.fRedirectURL;
result &= fRedirectStatus == env.fRedirectStatus;
result &= fReferrer == env.fReferrer;
result &= fCookie == env.fCookie;
return result;
}
cgicc::CgiEnvironment&
cgicc::CgiEnvironment::operator= (const CgiEnvironment& env)
{
fServerPort = env.fServerPort;
fContentLength = env.fContentLength;
fUsingHTTPS = env.fUsingHTTPS;
fServerSoftware = env.fServerSoftware;
fServerName = env.fServerName;
fGatewayInterface = env.fGatewayInterface;
fServerProtocol = env.fServerProtocol;
fRequestMethod = env.fRequestMethod;
fPathInfo = env.fPathInfo;
fPathTranslated = env.fPathTranslated;
fScriptName = env.fScriptName;
fQueryString = env.fQueryString;
fRemoteHost = env.fRemoteHost;
fRemoteAddr = env.fRemoteAddr;
fAuthType = env.fAuthType;
fRemoteUser = env.fRemoteUser;
fRemoteIdent = env.fRemoteIdent;
fContentType = env.fContentType;
fAccept = env.fAccept;
fUserAgent = env.fUserAgent;
fPostData = env.fPostData;
fRedirectRequest = env.fRedirectRequest;
fRedirectURL = env.fRedirectURL;
fRedirectStatus = env.fRedirectStatus;
fReferrer = env.fReferrer;
fCookie = env.fCookie;
fCookies.clear();
fCookies.reserve(env.fCookies.size());
parseCookies();
return *this;
}
void
cgicc::CgiEnvironment::parseCookies()
{
std::string data = fCookie;
if(false == data.empty()) {
std::string::size_type pos;
std::string::size_type oldPos = 0;
while(true) {
// find the ';' terminating a name=value pair
pos = data.find(";", oldPos);
// if no ';' was found, the rest of the string is a single cookie
if(std::string::npos == pos) {
parseCookie(data.substr(oldPos));
return;
}
// otherwise, the string contains multiple cookies
// extract it and add the cookie to the list
parseCookie(data.substr(oldPos, pos - oldPos));
// update pos (+1 to skip ';')
oldPos = pos + 1;
}
}
}
void
cgicc::CgiEnvironment::parseCookie(const std::string& data)
{
// find the '=' separating the name and value
std::string::size_type pos = data.find("=", 0);
// if no '=' was found, return
if(std::string::npos == pos)
return;
// skip leading whitespace - " \f\n\r\t\v"
std::string::size_type wscount = 0;
std::string::const_iterator data_iter;
for(data_iter = data.begin(); data_iter != data.end(); ++data_iter,++wscount)
if(0 == std::isspace(*data_iter))
break;
// Per RFC 2091, do not unescape the data (thanks to afm@othello.ch)
std::string name = data.substr(wscount, pos - wscount);
std::string value = data.substr(++pos);
fCookies.push_back(HTTPCookie(name, value));
}
// Read in all the environment variables
void
cgicc::CgiEnvironment::readEnvironmentVariables(CgiInput *input)
{
fServerSoftware = input->getenv("SERVER_SOFTWARE");
fServerName = input->getenv("SERVER_NAME");
fGatewayInterface = input->getenv("GATEWAY_INTERFACE");
fServerProtocol = input->getenv("SERVER_PROTOCOL");
std::string port = input->getenv("SERVER_PORT");
fServerPort = std::atol(port.c_str());
fRequestMethod = input->getenv("REQUEST_METHOD");
fPathInfo = input->getenv("PATH_INFO");
fPathTranslated = input->getenv("PATH_TRANSLATED");
fScriptName = input->getenv("SCRIPT_NAME");
fQueryString = input->getenv("QUERY_STRING");
fRemoteHost = input->getenv("REMOTE_HOST");
fRemoteAddr = input->getenv("REMOTE_ADDR");
fAuthType = input->getenv("AUTH_TYPE");
fRemoteUser = input->getenv("REMOTE_USER");
fRemoteIdent = input->getenv("REMOTE_IDENT");
fContentType = input->getenv("CONTENT_TYPE");
std::string length = input->getenv("CONTENT_LENGTH");
fContentLength = std::atol(length.c_str());
fAccept = input->getenv("HTTP_ACCEPT");
fUserAgent = input->getenv("HTTP_USER_AGENT");
fRedirectRequest = input->getenv("REDIRECT_REQUEST");
fRedirectURL = input->getenv("REDIRECT_URL");
fRedirectStatus = input->getenv("REDIRECT_STATUS");
fReferrer = input->getenv("HTTP_REFERER");
fCookie = input->getenv("HTTP_COOKIE");
fAcceptLanguageString = input->getenv("HTTP_ACCEPT_LANGUAGE");
// Win32 bug fix by Peter Goedtkindt
std::string https = input->getenv("HTTPS");
if(stringsAreEqual(https, "on"))
fUsingHTTPS = true;
else
fUsingHTTPS = false;
}
void
cgicc::CgiEnvironment::save(const std::string& filename) const
{
std::ofstream file( filename.c_str(), std::ios::binary |std::ios::out );
if( ! file )
throw std::runtime_error("I/O error");
writeLong(file, fContentLength);
writeLong(file, fServerPort);
writeLong(file, (unsigned long) usingHTTPS());
writeString(file, fServerSoftware);
writeString(file, fServerName);
writeString(file, fGatewayInterface);
writeString(file, fServerProtocol);
writeString(file, fRequestMethod);
writeString(file, fPathInfo);
writeString(file, fPathTranslated);
writeString(file, fScriptName);
writeString(file, fQueryString);
writeString(file, fRemoteHost);
writeString(file, fRemoteAddr);
writeString(file, fAuthType);
writeString(file, fRemoteUser);
writeString(file, fRemoteIdent);
writeString(file, fContentType);
writeString(file, fAccept);
writeString(file, fUserAgent);
writeString(file, fRedirectRequest);
writeString(file, fRedirectURL);
writeString(file, fRedirectStatus);
writeString(file, fReferrer);
writeString(file, fCookie);
if(stringsAreEqual(fRequestMethod, "post") || stringsAreEqual(fRequestMethod, "put"))
writeString(file, fPostData);
if(file.bad() || file.fail())
throw std::runtime_error("I/O error");
file.close();
}
void
cgicc::CgiEnvironment::restore(const std::string& filename)
{
std::ifstream file( filename.c_str(), std::ios::binary | std::ios::in );
if( ! file )
throw std::runtime_error("I/O error");
file.flags(file.flags() & std::ios::skipws);
fContentLength = readLong(file);
fServerPort = readLong(file);
fUsingHTTPS = (bool) readLong(file);
fServerSoftware = readString(file);
fServerName = readString(file);
fGatewayInterface = readString(file);
fServerProtocol = readString(file);
fRequestMethod = readString(file);
fPathInfo = readString(file);
fPathTranslated = readString(file);
fScriptName = readString(file);
fQueryString = readString(file);
fRemoteHost = readString(file);
fRemoteAddr = readString(file);
fAuthType = readString(file);
fRemoteUser = readString(file);
fRemoteIdent = readString(file);
fContentType = readString(file);
fAccept = readString(file);
fUserAgent = readString(file);
fRedirectRequest = readString(file);
fRedirectURL = readString(file);
fRedirectStatus = readString(file);
fReferrer = readString(file);
fCookie = readString(file);
if(stringsAreEqual(fRequestMethod, "post") || stringsAreEqual(fRequestMethod, "put"))
fPostData = readString(file);
file.close();
fCookies.clear();
fCookies.reserve(10);
parseCookies();
}

View File

@ -0,0 +1,580 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: CgiEnvironment.h,v 1.21 2014/04/23 20:55:03 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _CGIENVIRONMENT_H_
#define _CGIENVIRONMENT_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file CgiEnvironment.h
* \brief Class encapsulating the CGI runtime environment
*
* The \c CgiEnvironment class encapsulates the environment of
* the CGI application as described by the HTTP server. \c CgiEnvironment
* contains the \c GET or \c POST data along with all environment variables
* set by the HTTP server specified in the CGI specification.
*/
#include <string>
#include <vector>
#include <cstdlib>
#include "CgiDefs.h"
#include "CgiUtils.h"
#include "CgiInput.h"
#include "HTTPCookie.h"
namespace cgicc {
#ifdef WIN32
template class CGICC_API std::vector<HTTPCookie>;
#endif
// ============================================================
// Iterator typedefs
// ============================================================
//! A vector of HTTPCookie objects
typedef std::vector<HTTPCookie>::iterator cookie_iterator;
//! A vector of \c const HTTPCookie objects
typedef std::vector<HTTPCookie>::const_iterator const_cookie_iterator;
// ============================================================
// Class CgiEnvironment
// ============================================================
/*! \class CgiEnvironment CgiEnvironment.h cgicc/CgiEnvironment.h
* \brief Class encapsulating the CGI runtime environment
*
* The \c CgiEnvironment class encapsulates the environment of
* the CGI application as described by the HTTP server. \c CgiEnvironment
* contains the \c GET or \c POST data along with all environment variables
* set by the HTTP server specified in the CGI specification.
*/
class CGICC_API CgiEnvironment
{
public:
friend class Cgicc;
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Read in the CGI environment passed to the CGI application
* by the server
*
* This function is not usually called directly; instead, an object of type
* CgiEnvironment is retrieved by calling the \c getEnvironment() method
* on Cgicc.
* If you are using %cgicc with FastCGI, you will need to pass
* a \c CgiInput subclass that %cgicc will use to read input. If
* \c input is omitted, standard input and environment
* variables will be used.
* \param input A CgiInput object to use for reading input
* \see Cgicc::getEnvironment
*/
CgiEnvironment(CgiInput *input);
/*!
* \brief Copy constructor.
*
* Sets the values of this CgiEnvironment to those of \c env.
* \param env The CgiEnvironment to copy.
*/
inline
CgiEnvironment(const CgiEnvironment& env)
{ operator=(env); }
/*!
* \brief Destructor
*
* Delete this CgiEnvironment object
*/
~CgiEnvironment();
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Compare two CgiEnvironments for equality.
*
* CgiEnvironments are equal if they have the same environment variables.
* \param env The CgiEnvironment to compare to this one.
* \return \c true if the two CgiEnvironments are equal, \c false otherwise.
*/
bool
operator== (const CgiEnvironment& env) const;
/*!
* \brief Compare two CgiEnvironments for inequality.
*
* CgiEnvironments are equal if they have the same environment variables.
* \param env The CgiEnvironment to compare to this one.
* \return \c false if the two CgiEnvironments are equal, \c true otherwise.
*/
inline bool
operator!= (const CgiEnvironment& env) const
{ return ! operator==(env); }
#ifdef WIN32
/* Dummy operator for MSVC++ */
inline bool
operator< (const CgiEnvironment& env) const
{ return false; }
#endif
/*!
* \brief Assign one CgiEnvironment to another.
*
* Sets the environment variables in this CgiEnvironment to those of \c env.
* \param env The CgiEnvironment to copy.
* \return A reference to this.
*/
CgiEnvironment&
operator= (const CgiEnvironment& env);
//@}
// ============================================================
/*! \name Server Information
* Information on the server handling the HTTP/CGI request
*/
//@{
/*!
* \brief Get the name and version of the HTTP server software
*
* For example, \c Apache/1.3.4
* \return The name of the server software
*/
inline std::string
getServerSoftware() const
{ return fServerSoftware; }
/*!
* \brief Get the hostname, DNS name or IP address of the HTTP server
*
* This is \e not a URL, for example \c www.gnu.org (no leading http://)
* \return The name of the server
*/
inline std::string
getServerName() const
{ return fServerName; }
/*!
* \brief Get the name and version of the gateway interface.
*
* This is usually \c CGI/1.1
* \return The name and version of the gateway interface
*/
inline std::string
getGatewayInterface() const
{ return fGatewayInterface;}
/*!
* \brief Get the name and revision of the protocol used for this request.
*
* This is usually \c HTTP/1.0 or \c HTTP/1.1
* \return The protocol in use
*/
inline std::string
getServerProtocol() const
{ return fServerProtocol; }
/*!
* \brief Get the port number on the server to which this request was sent.
*
* This will usually be 80.
* \return The port number
*/
inline unsigned long
getServerPort() const
{ return fServerPort; }
/*!
* \brief Determine if this is a secure request
*
* A secure request is usually made using SSL via HTTPS
* \return \c true if this connection is via https, \c false otherwise
*/
inline bool
usingHTTPS() const
{ return fUsingHTTPS; }
//@}
// ============================================================
/*! \name CGI Query Information
* Information specific to this CGI query
*/
//@{
/*!
* \brief Get the HTTP cookies associated with this query, if any.
*
* The string returned by this method may contain multiple cookies; it is
* recommended to use the method getCookieList() instead, which returns
* a \c vector<HTTPCookie>.
* \return The HTTP cookies
* \see getCookieList
*/
inline std::string
getCookies() const
{ return fCookie; }
/*!
* \brief Get a \c vector containing the HTTP cookies
* associated with this query
*
* This vector may be empty
* \return A \c vector containing the HTTP cookies associated with this
* query
* \see HTTPCookie
*/
inline const std::vector<HTTPCookie>&
getCookieList() const
{ return fCookies; }
/*!
* \brief Get the request method used for this query.
*
* This is usually one of \c GET or \c POST
* \return The request method
*/
inline std::string
getRequestMethod() const
{ return fRequestMethod; }
/*!
* \brief Get the extra path information for this request, given by the
* client.
*
* For example, in the string \c foo.cgi/cgicc the path information is
* \c cgicc.
* \return The absolute path info
*/
inline std::string
getPathInfo() const
{ return fPathInfo; }
/*!
* \brief Get the translated path information (virtual to physical mapping).
*
* For example, \c www.gnu.org may be translated to \c /htdocs/index.html
* \return The translated path info
*/
inline std::string
getPathTranslated() const
{ return fPathTranslated; }
/*!
* \brief Get the full path to this CGI application
*
* This is useful for self-referencing URIs
* \return The full path of this application
*/
inline std::string
getScriptName() const
{ return fScriptName; }
/*!
* \brief Get the query string for this request.
*
* The query string follows the <tt>?</tt> in the URI which called this
* application. This is usually only valid for scripts called with
* the \c GET method. For example, in the string \c foo.cgi?cgicc=yes
* the query string is \c cgicc=yes.
* @return The query string
*/
inline std::string
getQueryString() const
{ return fQueryString; }
/*!
* \brief Get the length of the data read from standard input, in chars.
*
* This is usually only valid for scripts called with the POST method.
* \return The data length
*/
inline unsigned long
getContentLength() const
{ return fContentLength; }
/*!
* \brief Get the content type of the submitted information.
*
* For applications called via the GET method, this information is
* irrelevant. For applications called with the POST method, this is
* specifies the MIME type of the information,
* usually \c application/x-www-form-urlencoded or as specified by
* getContentType().
* \return The content type
* \see getContentType
*/
inline std::string
getContentType() const
{ return fContentType; }
/*!
* \brief Get the data passed to the CGI application via standard input.
*
* This data is of MIME type \c getContentType().
* \return The post data.
*/
inline std::string
getPostData() const
{ return fPostData; }
//@}
// ============================================================
/*! \name Server Specific Information
* Information dependent on the type of HTTP server in use
*/
//@{
/*!
* \brief Get the URL of the page which called this CGI application.
*
* Depending on the HTTP server software, this value may not be set.
* \return The URI which called this application.
*/
inline std::string
getReferrer() const
{ return fReferrer; }
//@}
// ============================================================
/*! \name Remote User Information
* Information about the user making the CGI request
*/
//@{
/*!
* \brief Get the hostname of the remote machine making this request
*
* This may be either an IP address or a hostname
* \return The remote host
*/
inline std::string
getRemoteHost() const
{ return fRemoteHost; }
/*!
* \brief Get the IP address of the remote machine making this request
*
* This is a standard IP address of the form \c 123.123.123.123
* \return The remote IP address
*/
inline std::string
getRemoteAddr() const
{ return fRemoteAddr; }
/*!
* \brief Get the protocol-specific user authentication method used.
*
* This is only applicable if the server supports user authentication,
* and the user has authenticated.
* \return The authorization type
*/
inline std::string
getAuthType() const
{ return fAuthType; }
/*!
* \brief Get the authenticated remote user name.
*
* This is only applicable if the server supports user authentication,
* and the user has authenticated.
* \return The remote username
*/
inline std::string
getRemoteUser() const
{ return fRemoteUser; }
/*!
* \brief Get the remote user name retrieved from the server.
*
* This is only applicable if the server supports RFC 931
* identification. This variable should \e only be used
* for logging purposes.
* \return The remote identification
* \see RFC 1431 at
* http://info.internet.isi.edu:80/in-notes/rfc/files/rfc1413.txt
*/
inline std::string
getRemoteIdent() const
{ return fRemoteIdent; }
/*!
* \brief Get the MIME data types accepted by the client's browser.
*
* For example <TT>image/gif, image/x-xbitmap, image/jpeg, image/pjpeg</TT>
* \return The accepted data types
*/
inline std::string
getAccept() const
{ return fAccept; }
/*!
* \brief Get the name of the browser used for this CGI request.
*
* For example <TT>Mozilla/5.0 (X11; U; Linux 2.4.0 i686; en-US; 0.8.1)
* Gecko/20010421</TT>
* \return The browser name
*/
inline std::string
getUserAgent() const
{ return fUserAgent; }
//@}
// ============================================================
/*! \name ErrorDocument Handling
* For a tutorial on ErrorDocument handling, see
* http://hoohoo.ncsa.uiuc.edu/cgi/ErrorCGI.html
*/
//@{
/*!
* \brief Get the redirect request.
*
* This will only be valid if you are using this script as a script
* to use in place of the default server messages.
* @return The redirect request.
*/
inline std::string
getRedirectRequest() const
{ return fRedirectRequest; }
/*!
* \brief Get the redirect URL.
*
* This will only be valid if you are using this script as a script
* to use in place of the default server messages.
* \return The redirect URL.
* \see http://hoohoo.ncsa.uiuc.edu/docs/setup/srm/ErrorDocument.html
*/
inline std::string
getRedirectURL() const
{ return fRedirectURL; }
/*!
* \brief Get the redirect status.
*
* This will only be valid if you are using this script as a script
* to use in place of the default server messages.
* \return The redirect status.
*/
inline std::string
getRedirectStatus() const
{ return fRedirectStatus; }
//@}
protected:
// ============================================================
/*! \name Saving and Restoring
* These are implementation methods only
*/
//@{
/*!
* \brief Implementation of save, for saving CGI environments
*
* This is called internally by Cgicc
* \param filename The name of the file to which to save
*/
void
save(const std::string& filename) const;
/*!
* \brief Implementation of restore, for restoring CGI environments
*
* This is called internally by Cgicc
* \param filename The name of the file from which to restore
*/
// Implementation of restore
void
restore(const std::string& filename);
//@}
// ============================================================
private:
// Parse the list of cookies from a string to a vector
void
parseCookies();
// Parse a single cookie string (name=value) pair
void
parseCookie(const std::string& data);
// Read in all the environment variables
void
readEnvironmentVariables(CgiInput *input);
unsigned long fServerPort;
unsigned long fContentLength;
bool fUsingHTTPS;
std::string fServerSoftware;
std::string fServerName;
std::string fGatewayInterface;
std::string fServerProtocol;
std::string fRequestMethod;
std::string fPathInfo;
std::string fPathTranslated;
std::string fScriptName;
std::string fQueryString;
std::string fRemoteHost;
std::string fRemoteAddr;
std::string fAuthType;
std::string fRemoteUser;
std::string fRemoteIdent;
std::string fContentType;
std::string fAccept;
std::string fUserAgent;
std::string fPostData;
std::string fRedirectRequest;
std::string fRedirectURL;
std::string fRedirectStatus;
std::string fReferrer;
std::string fCookie;
std::vector<HTTPCookie> fCookies;
std::string fAcceptLanguageString;
};
} // namespace cgicc
#endif /* ! _CGIENVIRONMENT_H_ */

View File

@ -0,0 +1,53 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: CgiInput.cpp,v 1.9 2014/04/23 20:55:03 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USAa
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include <iostream>
#include <cstdlib>
#include "CgiInput.h"
// ========== Destructor
cgicc::CgiInput::~CgiInput()
{}
// ========== Members
size_t
cgicc::CgiInput::read(char *data,
size_t length)
{
std::cin.read(data, length);
return std::cin.gcount();
}
std::string
cgicc::CgiInput::getenv(const char *varName)
{
char *var = std::getenv(varName);
return (0 == var) ? std::string("") : var;
}

View File

@ -0,0 +1,164 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: CgiInput.h,v 1.8 2014/04/23 20:55:03 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _CGIINPUT_H_
#define _CGIINPUT_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file CgiInput.h
* \brief Class that abstracts a data source
*
* This class allows the data source for the CGI application to be
* something other than standard input.
*/
#include <string>
#include "CgiDefs.h"
namespace cgicc {
// ============================================================
// Class CgiInput
// ============================================================
/*! \class CgiInput CgiInput.h cgicc/CgiInput.h
* \brief Class that abstracts a data source
*
* The \c CgiInput class is an abstraction for all input data to the
* CGI application. This allows input data to come from something other than
* standard input (cin). This is useful, in fact necessary, when using
* %cgicc with FastCgi.
* Library users wishing to exploit this functionality should create a
* subclass and override the \c read and \c getenv methods.
*/
class CGICC_API CgiInput
{
public:
// ============================================================
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Constructor
*
* Create a new CgiInput object
*/
inline
CgiInput()
{}
/*!
* \brief Copy constructor
*
* If you subclass CgiInput, you <strong>must</strong> overload
* operator=
* \param input The CgiInput object to copy
*/
inline
CgiInput(const CgiInput& input)
{ operator=(input); }
/*!
* \brief Destructor
*
* Delete this CgiInput object
*/
virtual ~CgiInput();
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Compare two CgiInput objects for equality
*
* In the default implementation all CgiInput objects are equal
* \param input The CgiInput object to compare to this one
* \return \c true
*/
inline bool
operator== (const CgiInput& /*input*/) const
{ return true; }
/*!
* \brief Compare two CgiInput objects for inequality
*
* In the default implementation all CgiInput objects are equal
* \param input The CgiInput object to compare to this one
* \return \c false
*/
inline bool
operator!= (const CgiInput& input) const
{ return ! operator==(input); }
/*!
* \brief Assign one CgiInput to another
*
* Does nothing in the default implementation
* \param input The CgiInput object to copy
* \return A reference to this.
*/
inline CgiInput&
operator= (const CgiInput& /*input*/)
{ return *this; }
//@}
// ============================================================
/*! \name Data Sources */
//@{
/*!
* \brief Read data from a data source
*
* In the default implementation, this is a wrapper for \c cin.read()
* \param data The target buffer
* \param length The number of characters to read
* \return The number of characters read
*/
virtual size_t read(char *data, size_t length);
/*!
* \brief Query the value of an environment variable
*
* In the default implementation, this is a wrapper for std::getenv()
* \param varName The name of an environment variable
* \return The value of the requested environment variable, or an empty
* string if not found.
*/
virtual std::string getenv(const char *varName);
//@}
};
} // namespace cgicc
#endif /* ! _CGIINPUT_H_ */

View File

@ -0,0 +1,282 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: CgiUtils.cpp,v 1.20 2014/04/23 20:55:03 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include <stdexcept>
#include <memory>
#include <vector>
#include <iterator> // for distance
#include <cctype> // for toupper, isxdigit
#include "CgiUtils.h"
// case-insensitive string comparison
// This code based on code from
// "The C++ Programming Language, Third Edition" by Bjarne Stroustrup
bool
cgicc::stringsAreEqual(const std::string& s1,
const std::string& s2)
{
std::string::const_iterator p1 = s1.begin();
std::string::const_iterator p2 = s2.begin();
std::string::const_iterator l1 = s1.end();
std::string::const_iterator l2 = s2.end();
while(p1 != l1 && p2 != l2) {
if(std::toupper(*(p1++)) != std::toupper(*(p2++)))
return false;
}
return (s2.size() == s1.size()) ? true : false;
}
// case-insensitive string comparison
bool
cgicc::stringsAreEqual(const std::string& s1,
const std::string& s2,
size_t n)
{
std::string::const_iterator p1 = s1.begin();
std::string::const_iterator p2 = s2.begin();
bool good = (n <= s1.length() && n <= s2.length());
std::string::const_iterator l1 = good ? (s1.begin() + n) : s1.end();
std::string::const_iterator l2 = good ? (s2.begin() + n) : s2.end();
while(p1 != l1 && p2 != l2) {
if(std::toupper(*(p1++)) != std::toupper(*(p2++)))
return false;
}
return good;
}
std::string
cgicc::charToHex(char c)
{
std::string result;
char first, second;
first = (c & 0xF0) / 16;
first += first > 9 ? 'A' - 10 : '0';
second = c & 0x0F;
second += second > 9 ? 'A' - 10 : '0';
result.append(1, first);
result.append(1, second);
return result;
}
char
cgicc::hexToChar(char first,
char second)
{
int digit;
digit = (first >= 'A' ? ((first & 0xDF) - 'A') + 10 : (first - '0'));
digit *= 16;
digit += (second >= 'A' ? ((second & 0xDF) - 'A') + 10 : (second - '0'));
return static_cast<char>(digit);
}
/*
From the HTML standard:
<http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1>
application/x-www-form-urlencoded
This is the default content type. Forms submitted with this content
type must be encoded as follows:
1. Control names and values are escaped. Space characters are
replaced by `+', and then reserved characters are escaped as
described in [RFC1738], section 2.2: Non-alphanumeric characters
are replaced by `%HH', a percent sign and two hexadecimal digits
representing the ASCII code of the character. Line breaks are
represented as "CR LF" pairs (i.e., `%0D%0A').
2. The control names/values are listed in the order they appear in
the document. The name is separated from the value by `=' and
name/value pairs are separated from each other by `&'.
Note RFC 1738 is obsoleted by RFC 2396. Basically it says to
escape out the reserved characters in the standard %xx format. It
also says this about the query string:
query = *uric
uric = reserved | unreserved | escaped
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
"$" | ","
unreserved = alphanum | mark
mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
"(" | ")"
escaped = "%" hex hex */
std::string
cgicc::form_urlencode(const std::string& src)
{
std::string result;
std::string::const_iterator iter;
for(iter = src.begin(); iter != src.end(); ++iter) {
switch(*iter) {
case ' ':
result.append(1, '+');
break;
// alnum
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9':
// mark
case '-': case '_': case '.': case '!': case '~': case '*': case '\'':
case '(': case ')':
result.append(1, *iter);
break;
// escape
default:
result.append(1, '%');
result.append(charToHex(*iter));
break;
}
}
return result;
}
std::string
cgicc::form_urldecode(const std::string& src)
{
std::string result;
std::string::const_iterator iter;
char c;
for(iter = src.begin(); iter != src.end(); ++iter) {
switch(*iter) {
case '+':
result.append(1, ' ');
break;
case '%':
// Don't assume well-formed input
if(std::distance(iter, src.end()) >= 2
&& std::isxdigit(*(iter + 1)) && std::isxdigit(*(iter + 2))) {
c = *++iter;
result.append(1, hexToChar(c, *++iter));
}
// Just pass the % through untouched
else {
result.append(1, '%');
}
break;
default:
result.append(1, *iter);
break;
}
}
return result;
}
// locate data between separators, and return it
std::string
cgicc::extractBetween(const std::string& data,
const std::string& separator1,
const std::string& separator2)
{
std::string result;
std::string::size_type start, limit;
start = data.find(separator1, 0);
if(std::string::npos != start) {
start += separator1.length();
limit = data.find(separator2, start);
if(std::string::npos != limit)
result = data.substr(start, limit - start);
}
return result;
}
// write a string
void
cgicc::writeString(std::ostream& out,
const std::string& s)
{
out << s.length() << ' ';
out.write(s.data(), s.length());
}
// write a long
void
cgicc::writeLong(std::ostream& out,
unsigned long l)
{
out << l << ' ';
}
// read a string
std::string
cgicc::readString(std::istream& in)
{
std::string::size_type dataSize = 0;
in >> dataSize;
in.get(); // skip ' '
// Avoid allocation of a zero-length vector
if(0 == dataSize) {
return std::string();
}
// Don't use auto_ptr, but vector instead
// Bug reported by bostjan@optonline.net / fix by alexoss@verizon.net
std::vector<char> temp(dataSize);
in.read(&temp[0], dataSize);
if(static_cast<std::string::size_type>(in.gcount()) != dataSize) {
throw std::runtime_error("I/O error");
}
return std::string(&temp[0], dataSize);
}
// read a long
unsigned long
cgicc::readLong(std::istream& in)
{
unsigned long l;
in >> l;
in.get(); // skip ' '
return l;
}

View File

@ -0,0 +1,208 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: CgiUtils.h,v 1.17 2014/04/23 20:55:03 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _CGIUTILS_H_
#define _CGIUTILS_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file CgiUtils.h
* \brief A collection of utility functions.
*
* These utility functions are used internally by cgicc to
* decode posted form data, and to read/write from streams.
*/
#include <new>
#include <string>
#include <fstream>
#include "CgiDefs.h"
namespace cgicc {
/*!
* \brief Compare two strings for equality, ignoring case.
*
* For case-sensitive comparison, use (s1 == s2);
* \param s1 The first string to compare
* \param s2 The second string to compare
* \return \c true if the strings are equal, \c false if they are not
*/
CGICC_API bool
stringsAreEqual(const std::string& s1,
const std::string& s2);
/*!
* \brief Compare two strings for equality, ignoring case.
*
* For case-sensitive comparison, use (s1 == s2);
* \param s1 The first string to compare
* \param s2 The second string to compare
* \param n The number of characters to compare.
* \return \c true if the strings are equal, \c false if they are not
*/
CGICC_API bool
stringsAreEqual(const std::string& ss1,
const std::string& ss2,
size_t n);
/*!
* \brief Convert encoded characters in form data to normal ASCII.
*
* For example, "%21" is converted to '!' and '+' is converted to a space.
* Normally, this is called internally to decode the query string or post
* data.
* \param src The src string containing the encoded characters
* \return The converted string
*/
CGICC_API std::string
form_urldecode(const std::string& src);
/*!
* \brief Convert an ASCII string to a URL-safe string.
*
* For example, '!' is converted to "%21" and ' ' is converted to '+'.
* \param src The src string containing the characters to encode
* \return The converted string
*/
CGICC_API std::string
form_urlencode(const std::string& src);
/*!
* \brief Convert an ASCII character to its hexadecimal equivalent.
*
* For example, after the call
* \code
* string s = charToHex(':');
* \endcode
* \c s will have a value of "3A".
* Normally, this is called internally to encode characters by
* escapeString.
* \param c The character to encode
* \return A string representing the hexadecimal value of c
*/
CGICC_API std::string
charToHex(char c);
/*!
* \brief Convert a hex-encoded character to its ASCII equivalent.
*
* For example, after the call
* \code
* char c = hexToChar('2', '1');
* \endcode
* \c c will have a value of '!'.
* Normally, this is called internally to decode encoded characters in
* the query string or post data.
* \param first The first hex digit
* \param second The second hex digit
* \return The ASCII character
*/
CGICC_API char
hexToChar(char first,
char second);
/*!
* \brief Extract a substring contained within two separators.
*
* For example, after the call
* \code
* std::string data = "11foo22";
* std::string res;
* res = extractBetween(data, "11", "22");
* \endcode
* \c res will be "foo".
* \param data The data to search.
* \param separator1 The first logical separator.
* \param separator2 The second logical separator.
* \return The substring between the separators.
*/
std::string
extractBetween(const std::string& data,
const std::string& separator1,
const std::string& separator2);
/*!
* \brief Extract a substring contained between a separator.
*
* This function is used internally to decode \c multipart/form-data
* \param data The data to search.
* \param separator The separator.
* \return The substring between the separator.
*/
inline std::string
extractBetween(const std::string& datas,
const std::string& separators)
{ return extractBetween(datas, separators, separators); }
/*!
* \brief Write a string to an ostream.
*
* This function is used internally for saving environments.
* \param out The ostream to which to write.
* \param s The string to write.
*/
void
writeString(std::ostream& out,
const std::string& s);
/*!
* \brief Write a long to an ostream.
*
* This function is used internally for saving environments.
* \param out The ostream to which to write.
* \param l The long to write.
*/
void
writeLong(std::ostream& out,
unsigned long l);
/*!
* \brief Read a string from an istream.
*
* This function is used internally by cgicc for restoring environments.
* \param in The istream from which to read.
* \return The string read.
*/
std::string
readString(std::istream& in);
/*!
* \brief Read a long from an istream.
*
* This function is used internally by cgicc for restoring environments.
* \param in The istream from which to read.
* \return The long read.
*/
unsigned long
readLong(std::istream& in);
} // namespace cgicc
#endif /* ! _CGIUTILS_H_ */

View File

@ -0,0 +1,506 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: Cgicc.cpp,v 1.34 2014/04/23 20:55:04 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <new>
#include <algorithm>
#include <functional>
#include <iterator>
#include <stdexcept>
#include "CgiUtils.h"
#include "Cgicc.h"
namespace cgicc {
// ============================================================
// Class FE_nameCompare
// ============================================================
class FE_nameCompare : public std::unary_function<FormEntry, bool>
{
public:
inline explicit FE_nameCompare(const std::string& name)
: fName(name) {}
inline bool operator() (const FormEntry& entry) const
{ return stringsAreEqual(fName, entry.getName()); }
private:
std::string fName;
};
// ============================================================
// Class FE_valueCompare
// ============================================================
class FE_valueCompare : public std::unary_function<FormEntry, bool>
{
public:
inline explicit FE_valueCompare(const std::string& value)
: fValue(value) {}
inline bool operator() (const FormEntry& entry) const
{ return stringsAreEqual(fValue, entry.getValue()); }
private:
std::string fValue;
};
// ============================================================
// Class FF_compare
// ============================================================
class FF_compare : public std::unary_function<FormFile, bool>
{
public:
inline explicit FF_compare(const std::string& name)
: fName(name) {}
inline bool operator() (const FormFile& entry) const
{ return stringsAreEqual(fName, entry.getName()); }
private:
std::string fName;
};
// ============================================================
// Function copy_if (handy, missing from STL)
// ============================================================
// This code taken directly from
// "The C++ Programming Language, Third Edition" by Bjarne Stroustrup
template<class In, class Out, class Pred>
Out
copy_if(In first,
In last,
Out res,
Pred p)
{
while(first != last) {
if(p(*first))
*res++ = *first;
++first;
}
return res;
}
} // namespace cgicc
// ============================================================
// Class MultipartHeader
// ============================================================
class cgicc::MultipartHeader
{
public:
MultipartHeader(const std::string& disposition,
const std::string& name,
const std::string& filename,
const std::string& cType);
inline
MultipartHeader(const MultipartHeader& head)
{ operator=(head); }
~MultipartHeader();
MultipartHeader&
operator= (const MultipartHeader& head);
inline std::string
getContentDisposition() const
{ return fContentDisposition; }
inline std::string
getName() const
{ return fName; }
inline std::string
getFilename() const
{ return fFilename; }
inline std::string
getContentType() const
{ return fContentType; }
private:
std::string fContentDisposition;
std::string fName;
std::string fFilename;
std::string fContentType;
};
cgicc::MultipartHeader::MultipartHeader(const std::string& disposition,
const std::string& name,
const std::string& filename,
const std::string& cType)
: fContentDisposition(disposition),
fName(name),
fFilename(filename),
fContentType(cType)
{}
cgicc::MultipartHeader::~MultipartHeader()
{}
cgicc::MultipartHeader&
cgicc::MultipartHeader::operator= (const MultipartHeader& head)
{
fContentDisposition = head.fContentDisposition;
fName = head.fName;
fFilename = head.fFilename;
fContentType = head.fContentType;
return *this;
}
// ============================================================
// Class Cgicc
// ============================================================
cgicc::Cgicc::Cgicc(CgiInput *input)
: fEnvironment(input)
{
// this can be tweaked for performance
fFormData.reserve(20);
fFormFiles.reserve(2);
parseFormInput(fEnvironment.getPostData(), fEnvironment.getContentType());
parseFormInput(fEnvironment.getQueryString());
}
cgicc::Cgicc::~Cgicc()
{}
cgicc::Cgicc&
cgicc::Cgicc::operator= (const Cgicc& cgi)
{
this->fEnvironment = cgi.fEnvironment;
fFormData.clear();
fFormFiles.clear();
parseFormInput(fEnvironment.getPostData(), fEnvironment.getContentType());
parseFormInput(fEnvironment.getQueryString());
return *this;
}
const char*
cgicc::Cgicc::getCompileDate() const
{ return __DATE__; }
const char*
cgicc::Cgicc::getCompileTime() const
{ return __TIME__; }
const char*
cgicc::Cgicc::getVersion() const
{ return VERSION; }
const char*
cgicc::Cgicc::getHost() const
{ return HOST; }
void
cgicc::Cgicc::save(const std::string& filename) const
{
fEnvironment.save(filename);
}
void
cgicc::Cgicc::restore(const std::string& filename)
{
fEnvironment.restore(filename);
// clear the current data and re-parse the enviroment
fFormData.clear();
fFormFiles.clear();
parseFormInput(fEnvironment.getPostData(), fEnvironment.getContentType());
parseFormInput(fEnvironment.getQueryString());
}
bool
cgicc::Cgicc::queryCheckbox(const std::string& elementName) const
{
const_form_iterator iter = getElement(elementName);
return (iter != fFormData.end() && stringsAreEqual(iter->getValue(), "on"));
}
std::string
cgicc::Cgicc::operator() (const std::string& name) const
{
std::string result;
const_form_iterator iter = getElement(name);
if(iter != fFormData.end() && false == iter->isEmpty())
result = iter->getValue();
return result;
}
cgicc::form_iterator
cgicc::Cgicc::getElement(const std::string& name)
{
return std::find_if(fFormData.begin(), fFormData.end(),FE_nameCompare(name));
}
cgicc::const_form_iterator
cgicc::Cgicc::getElement(const std::string& name) const
{
return std::find_if(fFormData.begin(), fFormData.end(),FE_nameCompare(name));
}
bool
cgicc::Cgicc::getElement(const std::string& name,
std::vector<FormEntry>& result) const
{
return findEntries(name, true, result);
}
cgicc::form_iterator
cgicc::Cgicc::getElementByValue(const std::string& value)
{
return std::find_if(fFormData.begin(), fFormData.end(),
FE_valueCompare(value));
}
cgicc::const_form_iterator
cgicc::Cgicc::getElementByValue(const std::string& value) const
{
return std::find_if(fFormData.begin(), fFormData.end(),
FE_valueCompare(value));
}
bool
cgicc::Cgicc::getElementByValue(const std::string& value,
std::vector<FormEntry>& result) const
{
return findEntries(value, false, result);
}
cgicc::file_iterator
cgicc::Cgicc::getFile(const std::string& name)
{
return std::find_if(fFormFiles.begin(), fFormFiles.end(), FF_compare(name));
}
cgicc::const_file_iterator
cgicc::Cgicc::getFile(const std::string& name) const
{
return std::find_if(fFormFiles.begin(), fFormFiles.end(), FF_compare(name));
}
// implementation method
bool
cgicc::Cgicc::findEntries(const std::string& param,
bool byName,
std::vector<FormEntry>& result) const
{
// empty the target vector
result.clear();
if(byName) {
cgicc::copy_if(fFormData.begin(), fFormData.end(),
std::back_inserter(result),FE_nameCompare(param));
}
else {
cgicc::copy_if(fFormData.begin(), fFormData.end(),
std::back_inserter(result), FE_valueCompare(param));
}
return false == result.empty();
}
void
cgicc::Cgicc::parseFormInput(const std::string& data, const std::string &content_type)
{
std::string standard_type = "application/x-www-form-urlencoded";
std::string multipart_type = "multipart/form-data";
// Don't waste time on empty input
if(true == data.empty())
return;
// Standard content type = application/x-www-form-urlencoded
// It may not be explicitly specified
if(true == content_type.empty()
|| stringsAreEqual(content_type, standard_type,standard_type.length())) {
std::string name, value;
std::string::size_type pos;
std::string::size_type oldPos = 0;
// Parse the data in one fell swoop for efficiency
while(true) {
// Find the '=' separating the name from its value, also have to check for '&' as its a common misplaced delimiter but is a delimiter none the less
pos = data.find_first_of( "&=", oldPos);
// If no '=', we're finished
if(std::string::npos == pos)
break;
// Decode the name
// pos == '&', that means whatever is in name is the only name/value
if( data.at( pos ) == '&' )
{
const char * pszData = data.c_str() + oldPos;
while( *pszData == '&' ) // eat up extraneous '&'
{
++pszData; ++oldPos;
}
if( oldPos >= pos )
{ // its all &'s
oldPos = ++pos;
continue;
}
// this becomes an name with an empty value
name = form_urldecode(data.substr(oldPos, pos - oldPos));
fFormData.push_back(FormEntry(name, "" ) );
oldPos = ++pos;
continue;
}
name = form_urldecode(data.substr(oldPos, pos - oldPos));
oldPos = ++pos;
// Find the '&' or ';' separating subsequent name/value pairs
pos = data.find_first_of(";&", oldPos);
// Even if an '&' wasn't found the rest of the string is a value
value = form_urldecode(data.substr(oldPos, pos - oldPos));
// Store the pair
fFormData.push_back(FormEntry(name, value));
if(std::string::npos == pos)
break;
// Update parse position
oldPos = ++pos;
}
}
// File upload type = multipart/form-data
else if(stringsAreEqual(multipart_type, content_type,
multipart_type.length())){
// Find out what the separator is
std::string bType = "boundary=";
std::string::size_type pos = content_type.find(bType);
// Remove next sentence
std::string commatek=";";
// generate the separators
std::string sep1 = content_type.substr(pos + bType.length());
if (sep1.find(";")!=std::string::npos)
sep1=sep1.substr(0,sep1.find(";"));
sep1.append("\r\n");
sep1.insert(0, "--");
std::string sep2 = content_type.substr(pos + bType.length());
if (sep2.find(";")!=std::string::npos)
sep2=sep2.substr(0,sep2.find(";"));
sep2.append("--\r\n");
sep2.insert(0, "--");
// Find the data between the separators
std::string::size_type start = data.find(sep1);
std::string::size_type sepLen = sep1.length();
std::string::size_type oldPos = start + sepLen;
while(true) {
pos = data.find(sep1, oldPos);
// If sep1 wasn't found, the rest of the data is an item
if(std::string::npos == pos)
break;
// parse the data
parseMIME(data.substr(oldPos, pos - oldPos));
// update position
oldPos = pos + sepLen;
}
// The data is terminated by sep2
pos = data.find(sep2, oldPos);
// parse the data, if found
if(std::string::npos != pos) {
parseMIME(data.substr(oldPos, pos - oldPos));
}
}
}
cgicc::MultipartHeader
cgicc::Cgicc::parseHeader(const std::string& data)
{
std::string disposition;
disposition = extractBetween(data, "Content-Disposition: ", ";");
std::string name;
name = extractBetween(data, "name=\"", "\"");
std::string filename;
filename = extractBetween(data, "filename=\"", "\"");
std::string cType;
cType = extractBetween(data, "Content-Type: ", "\r\n\r\n");
// This is hairy: Netscape and IE don't encode the filenames
// The RFC says they should be encoded, so I will assume they are.
filename = form_urldecode(filename);
return MultipartHeader(disposition, name, filename, cType);
}
void
cgicc::Cgicc::parseMIME(const std::string& data)
{
// Find the header
std::string end = "\r\n\r\n";
std::string::size_type headLimit = data.find(end, 0);
// Detect error
if(std::string::npos == headLimit)
throw std::runtime_error("Malformed input");
// Extract the value - there is still a trailing CR/LF to be subtracted off
std::string::size_type valueStart = headLimit + end.length();
std::string value = data.substr(valueStart, data.length() - valueStart - 2);
// Parse the header - pass trailing CR/LF x 2 to parseHeader
MultipartHeader head = parseHeader(data.substr(0, valueStart));
if(head.getFilename().empty())
fFormData.push_back(FormEntry(head.getName(), value));
else
fFormFiles.push_back(FormFile(head.getName(),
head.getFilename(),
head.getContentType(),
value));
}

View File

@ -0,0 +1,452 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: Cgicc.h,v 1.20 2014/04/23 20:55:04 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _CGICC_H_
#define _CGICC_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file Cgicc.h
* \brief The main header file for the GNU %cgicc library
*/
/*
* The GNU cgicc library, by Stephen F. Booth <sbooth@gnu.org>
* http://www.cgicc.org
*
* The latest version can be found on your closest GNU mirror site.
* Please mail bug reports to <bug-cgicc@gnu.org>
*/
#include <vector>
#include <string>
#include "CgiDefs.h"
#include "FormEntry.h"
#include "FormFile.h"
#include "CgiInput.h"
#include "CgiEnvironment.h"
namespace cgicc {
#ifdef WIN32
template class CGICC_API std::vector<FormEntry>;
template class CGICC_API std::vector<FormFile>;
#endif
class MultipartHeader;
// ============================================================
// Iterator typedefs
// ============================================================
//! A vector of FormEntry objects
typedef std::vector<FormEntry>::iterator form_iterator;
//! A vector of \c const FormEntry objects
typedef std::vector<FormEntry>::const_iterator const_form_iterator;
//! A vector of FormFile objects
typedef std::vector<FormFile>::iterator file_iterator;
//! A vector of \c const FormFile objects
typedef std::vector<FormFile>::const_iterator const_file_iterator;
// ============================================================
// Class Cgicc
// ============================================================
/*! \class Cgicc Cgicc.h cgicc/Cgicc.h
* \brief The main class of the GNU %cgicc library
*
* Cgicc is used to retrieve information on specific HTML form elements
* (such as checkboxes, radio buttons, and text fields), on uploaded files,
* and to save, restore, and retrieve information on the CGI
* environment.
*
* Normally, you will instantiate an object of this type in
* \c main():
* \code
* int
* main(int argc, char **argv) {
* try {
* cgicc::Cgicc cgi;
* // do something with cgi
* }
*
* catch(const exception& e) {
* //handle the error
* }
* }
* \endcode
*/
class CGICC_API Cgicc {
public:
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Constructor
*
* If you are using %cgicc with FastCGI, you will need to pass
* a \c CgiInput subclass that %cgicc will use to read input. If
* \c input is omitted, standard input and environment
* variables will be used.
* \param input A CgiInput object to use for reading input
*/
Cgicc(CgiInput *input = 0);
/*!
* \brief Copy constructor.
*
* Sets the values of this Cgicc to those of \c cgi.
* \param env The Cgicc to copy.
*/
inline
Cgicc(const Cgicc& cgi)
: fEnvironment(cgi.fEnvironment)
{ operator=(cgi); }
/*!
* \brief Destructor
*
* Delete this Cgicc object
*/
~Cgicc();
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Compare two Cgiccs for equality.
*
* Cgiccs are equal if they represent the same environment.
* \param cgi The Cgicc to compare to this one.
* \return \c true if the two Cgiccs are equal, \c false otherwise.
*/
inline bool
operator== (const Cgicc& cgi) const
{ return this->fEnvironment == cgi.fEnvironment; }
/*!
* \brief Compare two Cgiccs for inequality.
*
* Cgiccs are equal if they represent the same environment.
* \param cgi The Cgicc to compare to this one.
* \return \c false if the two Cgiccs are equal, \c true otherwise.
*/
inline bool
operator!= (const Cgicc& cgi) const
{ return ! operator==(cgi); }
#ifdef WIN32
/* Dummy operator for MSVC++ */
inline bool
operator< (const Cgicc& cgi) const
{ return false; }
#endif
/*!
* \brief Assign one Cgicc to another.
*
* Sets the environment in this Cgicc to that of \c cgi.
* \param cgi The Cgicc to copy.
* \return A reference to this.
*/
Cgicc&
operator= (const Cgicc& cgi);
//@}
// ============================================================
/*! \name Library Information
* Information on this installation of %cgicc
*/
//@{
/*!
* \brief Get the date on which this library was compiled.
*
* This is a string of the form <TT>mmm dd yyyy</TT>.
* \return The compile date
*/
const char*
getCompileDate() const;
/*!
* \brief Get the time at which this library was compiled.
*
* This is a string of the form \c hh:mm:ss in 24-hour time.
* \return The compile time
*/
const char*
getCompileTime() const;
/*!
* \brief Get the version number of cgicc.
*
* The version number is a string of the form \c #.#.
* \return The version number
*/
const char*
getVersion() const;
/*!
* \brief Get the platform for which Cgicc was configured.
*
* The host is a string of the form \c processor-manufacturer-os
* return The host triplet.
*/
const char*
getHost() const;
//@}
// ============================================================
/*! \name Form Element Access
* Information on submitted form elements
*/
//@{
/*!
* \brief Query whether a checkbox is checked.
*
* \param elementName The name of the element to query
* \return \c true if the desired checkbox was checked, \c false if not
*/
bool
queryCheckbox(const std::string& elementName) const;
/*!
* \brief Find a radio button in a radio group, or a selected list item.
*
* \param name The name of the radio button or list item to find.
* \return An iterator referring to the desired element, if found.
*/
inline form_iterator
operator[] (const std::string& name)
{ return getElement(name); }
/*!
* \brief Find a radio button in a radio group, or a selected list item.
*
* \param name The name of the radio button or list item to find.
* \return The desired element, or an empty string if not found.
*/
std::string
operator() (const std::string& name) const;
/*!
* \brief Find a radio button in a radio group, or a selected list item.
*
* \param name The name of the radio button or list item to find.
* \return An iterator referring to the desired element, if found.
*/
inline const_form_iterator
operator[] (const std::string& name) const
{ return getElement(name); }
/*!
* \brief Find a radio button in a radio group, or a selected list item.
*
* \param name The name of the radio button or list item to find.
* \return An iterator referring to the desired element, if found.
*/
form_iterator
getElement(const std::string& name);
/*!
* \brief Find a radio button in a radio group, or a selected list item.
*
* \param name The name of the radio button or list item to find.
* \return A const_iterator referring to the desired element, if found.
*/
const_form_iterator
getElement(const std::string& name) const;
/*!
* \brief Find multiple checkboxes in a group or selected items in a list.
*
* \param name The name of the checkboxes or list to find.
* \param result A vector to hold the result.
* \return \c true if any elements were found, \c false if not.
*/
bool
getElement(const std::string& name,
std::vector<FormEntry>& result) const;
/*!
* \brief Find a radio button in a radio group, or a selected list item.
*
* \param value The value of the radio button or list item to find.
* \return An iterator referring to the desired element, if found.
*/
form_iterator
getElementByValue(const std::string& value);
/*!
* \brief Find a radio button in a radio group, or a selected list item.
*
* \param value The value of the radio button or list item to find.
* \return A const_iterator referring to the desired element, if found.
*/
const_form_iterator
getElementByValue(const std::string& value) const;
/*!
* \brief Find multiple checkboxes in a group or selected items in a list.
*
* \param value The value of the checkboxes or list to find.
* \param result A vector to hold the result.
* \return true if any elements were found, false if not.
*/
bool
getElementByValue(const std::string& value,
std::vector<FormEntry>& result) const;
/*!
* \brief Get all the submitted form entries, excluding files.
*
* \return A vector containing all the submitted elements.
*/
inline const std::vector<FormEntry>&
operator* () const
{ return fFormData; }
/*!
* \brief Get all the submitted form elements, excluding files.
*
* \return A vector containing all the submitted elements.
*/
inline const std::vector<FormEntry>&
getElements() const
{ return fFormData; }
//@}
// ============================================================
/*! \name Uploaded File Access */
//@{
/*!
* \brief Find an uploaded file.
*
* \param name The name of the file.
* \return An iterator referring to the desired file, if found.
*/
file_iterator
getFile(const std::string& name);
/*!
* \brief Find an uploaded file.
*
* \param name The name of the file.
* \return An iterator referring to the desired file, if found.
*/
const_file_iterator
getFile(const std::string& name) const;
/*!
* Get all uploaded files.
* \return A vector containing all the uploaded files.
*/
inline const std::vector<FormFile>&
getFiles() const
{ return fFormFiles; }
//@}
// ============================================================
/*! \name Environment Access */
//@{
/*!
* Get the current runtime environment.
* \return The current CGI environment.
*/
inline const CgiEnvironment&
getEnvironment() const
{ return fEnvironment;}
//@}
// ============================================================
/*! \name Save and Restore */
//@{
/*!
* \brief Save the current CGI environment to a file.
*
* This is useful for debugging CGI applications.
* \param filename The name of the file to which to save.
*/
void
save(const std::string& filename) const;
/*!
* \brief Restore from a previously-saved CGI environment.
*
* This is useful for debugging CGI applications.
* \param filename The name of the file from which to restore.
*/
void
restore(const std::string& filename);
//@}
private:
CgiEnvironment fEnvironment;
std::vector<FormEntry> fFormData;
std::vector<FormFile> fFormFiles;
// Convert query string into a list of FormEntries
void
parseFormInput(const std::string& data, const std::string& content_type = "application/x-www-form-urlencoded");
// Parse a multipart/form-data header
MultipartHeader
parseHeader(const std::string& data);
// Parse a (name=value) form entry
void
parsePair(const std::string& data);
// Parse a MIME entry for ENCTYPE=""
void
parseMIME(const std::string& data);
// Find elements in the list of entries
bool
findEntries(const std::string& param,
bool byName,
std::vector<FormEntry>& result) const;
};
} // namespace cgicc
#endif /* ! _CGICC_H_ */

View File

@ -0,0 +1,160 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: FormEntry.cpp,v 1.14 2014/04/23 20:55:04 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include <new>
#include <cstdlib>
#include "FormEntry.h"
// local macro for integer maximum
#define MAX(a, b) ((a) > (b) ? (a) : (b))
cgicc::FormEntry&
cgicc::FormEntry::operator= (const FormEntry& entry)
{
fName = entry.fName;
fValue = entry.fValue;
return *this;
}
long
cgicc::FormEntry::getIntegerValue(long min,
long max) const
{
long value = std::atol(fValue.c_str());
if(value > max)
value = max;
else if(value < min)
value = min;
return value;
}
long
cgicc::FormEntry::getIntegerValue(long min,
long max,
bool& bounded) const
{
long value = std::atol(fValue.c_str());
bounded = false;
if(value > max) {
value = max;
bounded = true;
}
else if(value < min) {
value = min;
bounded = true;
}
return value;
}
double
cgicc::FormEntry::getDoubleValue(double min,
double max) const
{
double value = std::atof(fValue.c_str());
if(value > max)
value = max;
else if(value < min)
value = min;
return value;
}
double
cgicc::FormEntry::getDoubleValue(double min,
double max,
bool& bounded) const
{
double value = std::atof(fValue.c_str());
bounded = false;
if(value > max) {
value = max;
bounded = true;
}
else if(value < min) {
value = min;
bounded = true;
}
return value;
}
std::string
cgicc::FormEntry::makeString(std::string::size_type maxLen,
bool allowNewlines) const
{
std::string::size_type len = 0;
std::string::size_type avail = maxLen;
std::string::size_type crCount = 0;
std::string::size_type lfCount = 0;
std::string::const_iterator src = fValue.begin();
std::string::const_iterator lim = fValue.end();
std::string dst;
while(src != lim && len < avail) {
// handle newlines
if('\r' == *src || '\n' == *src) {
crCount = 0;
lfCount = 0;
// Count the number of each kind of line break ('\r' and '\n')
while( ('\r' == *src || '\n' == *src) && (src != lim)) {
if('\r' == *src)
crCount++;
else
lfCount++;
++src;
}
// if newlines are allowed, add them
if(allowNewlines) {
// output the larger value
int lfsAdd = MAX(crCount, lfCount);
dst.append(lfsAdd, '\n');
len += lfsAdd;
}
}
// just append all other characters
else {
dst.append(1, *src);
++len;
++src;
}
}
return dst;
}

View File

@ -0,0 +1,327 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: FormEntry.h,v 1.15 2014/04/23 20:55:04 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _FORMENTRY_H_
#define _FORMENTRY_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file FormEntry.h
* \brief Class representing a single HTML form entry.
*
* FormEntry is an immutable class representing a single user entry
* in an HTML form element such as a text field, radio button, or a
* checkbox. A FormEntry is essentially a name/value pair, where the
* name is the name of the form element as specified in the HTML form
* itself, and the value is the user-entered or user-selected value.
*/
#include <iostream>
#include <string>
#include <climits>
#include <cfloat>
#include "CgiDefs.h"
#include "CgiUtils.h"
namespace cgicc {
// ============================================================
// Class FormEntry
// ============================================================
/*! \class FormEntry FormEntry.h cgicc/FormEntry.h
* \brief Class representing a single HTML form entry.
*
* FormEntry is an immutable class representing a single user entry
* in an HTML form element such as a text field, radio button, or a
* checkbox. A FormEntry is essentially a name/value pair, where the
* name is the name of the form element as specified in the HTML form
* itself, and the value is the user-entered or user-selected value.
*
* If a \c QUERY_STRING contained the fragment \c cgicc=yes the
* corresponding FormEntry would have a name of \c cgicc and a value
* of \c yes
*
* \sa FormFile
*/
class CGICC_API FormEntry
{
public:
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Default constructor
*
* Shouldn't be used.
*/
inline
FormEntry()
{}
/*!
* \brief Create a new FormEntry
*
* This is usually not called directly, but by Cgicc.
* \param name The name of the form element
* \param value The value of the form element
*/
inline
FormEntry(const std::string& name,
const std::string& value)
: fName(name), fValue(value)
{}
/*!
* \brief Copy constructor.
*
* Sets the name and value of this FormEntry to those of \c entry.
* \param entry The FormEntry to copy.
*/
inline
FormEntry(const FormEntry& entry)
{ operator=(entry); }
/*!
* \brief Destructor.
*
* Delete this FormEntry object
*/
inline
~FormEntry()
{}
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Compare two FormEntrys for equality.
*
* FormEntrys are equal if they have the same name and value.
* \param entry The FormEntry to compare to this one.
* \return \c true if the two FormEntrys are equal, \c false otherwise.
*/
inline bool
operator== (const FormEntry& entry) const
{ return stringsAreEqual(fName, entry.fName); }
/*!
* \brief Compare two FormEntrys for inequality.
*
* FormEntrys are equal if they have the same name and value.
* \param entry The FormEntry to compare to this one.
* \return \c false if the two FormEntrys are equal, \c true otherwise.
*/
inline bool
operator!= (const FormEntry& entry) const
{ return ! operator==(entry); }
#ifdef WIN32
/* Dummy operator for MSVC++ */
inline bool
operator< (const FormEntry& entry) const
{ return false; }
#endif
/*!
* \brief Assign one FormEntry to another.
*
* Sets the name and value of this FormEntry to those of \c entry.
* \param entry The FormEntry to copy.
* \return A reference to this.
*/
FormEntry&
operator= (const FormEntry& entry);
//@}
// ============================================================
/*! \name Accessor Methods
* Information on the form element
*/
//@{
/*!
* \brief Get the name of the form element.
*
* The name of the form element is specified in the HTML form that
* called the CGI application.
* \return The name of the form element.
*/
inline std::string
getName() const
{ return fName; }
/*!
* \brief Get the value of the form element as a string
*
* The value returned may contain line breaks.
* \return The value of the form element.
*/
inline std::string
getValue() const
{ return fValue; }
/*!
* \brief Get the value of the form element as a string
*
* The value returned may contain line breaks.
* \return The value of the form element.
*/
inline std::string
operator* () const
{ return getValue(); }
/*!
* \brief Get the value of the form element as a string
*
* The value returned will be truncated to a specific length.
* The value may contain line breaks.
* \param maxChars The maximum number of characters to return.
* \return The value of the form element, truncated to the specified length.
*/
inline std::string
getValue(std::string::size_type maxChars) const
{ return makeString(maxChars, true); }
/*!
* \brief Get the value of the form element as a string
*
* The value returned will be stripped of all line breaks.
* \return The value of the form element, stripped of all line breaks.
*/
inline std::string
getStrippedValue() const
{ return getStrippedValue(INT_MAX); }
/*!
* \brief Get the value of the form element as a string
*
* The value returned will be stripped of all line breaks
* and truncated to a specific length.
* \param maxChars The maximum number of characters to return.
* \return The value of the form element, stripped of all line breaks and
* truncated to the specified length.
*/
inline std::string
getStrippedValue(std::string::size_type maxChars) const
{ return makeString(maxChars, false); }
/*!
* \brief Get the value of the form element as an integer
*
* No syntax checking is performed on the string value.
* \param min The minimum value to return (optional).
* \param max The maximum value to return (optional).
* \return The integer value of the form element.
*/
long
getIntegerValue(long min = LONG_MIN,
long max = LONG_MAX) const;
/*!
* \brief Get the value of the form element as an integer
*
* No syntax checking is performed on the string value.
* \param min The minimum value to return.
* \param max The maximum value to return.
* \param bounded Set to \c true if the value was originally outside the
* limits, \c false otherwise
* \return The integer value of the form element.
*/
long
getIntegerValue(long min,
long max,
bool& bounded) const;
/*!
* \brief Get the value of the form element as a double
*
* No syntax checking is performed on the string value.
* \param min The minimum value to return (optional).
* \param max The maximum value to return (optional).
* \return The double value of the form element.
*/
double
getDoubleValue(double min = -DBL_MAX,
double max = DBL_MAX) const;
/*!
* \brief Get the value of the form element as a double
*
* No syntax checking is performed on the string value.
* \param min The minimum value to return.
* \param max The maximum value to return.
* \param bounded Set to \c true if the value was originally outside the
* limits, \c false otherwise
* \return The double value of the form element.
*/
double
getDoubleValue(double min,
double max,
bool& bounded) const;
/*!
* \brief Get the number of characters in the value of the form element.
*
* Note that a character may or may not equal one byte.
* \return The length of the value of the form element
*/
inline std::string::size_type
length() const
{ return fValue.length(); }
/*!
* \brief Determine if this form element is empty
*
* In an empty form element, length() == 0.
* \return \c true if this form element is empty, \c false otherwise.
*/
inline bool
isEmpty() const
{ return (0 == length()); }
//@}
private:
// utility function
std::string
makeString(std::string::size_type maxLen,
bool allowNewlines) const;
std::string fName; // the name of this form element
std::string fValue; // the value of this form element
};
} // namespace cgicc
#endif /* ! _FORMENTRY_H_ */

View File

@ -0,0 +1,65 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: FormFile.cpp,v 1.11 2014/04/23 20:55:04 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "FormFile.h"
#include "CgiUtils.h"
cgicc::FormFile::FormFile(const std::string& name,
const std::string& filename,
const std::string& dataType,
const std::string& data)
: fName(name),
fFilename(filename),
fData(data)
{
fDataType = dataType.empty() ? std::string("text/plain") : dataType;
}
bool
cgicc::FormFile::operator== (const FormFile& file) const
{
return (stringsAreEqual(fName, file.fName) &&
stringsAreEqual(fFilename, file.fFilename) &&
stringsAreEqual(fDataType, file.fDataType));
}
cgicc::FormFile&
cgicc::FormFile::operator= (const FormFile& file)
{
fName = file.fName;
fFilename = file.fFilename;
fDataType = file.fDataType;
fData = file.fData;
return *this;
}
void
cgicc::FormFile::writeToStream(std::ostream& out) const
{
out.write(getData().data(), getDataLength());
}

View File

@ -0,0 +1,237 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: FormFile.h,v 1.12 2014/04/23 20:55:04 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _FORMFILE_H_
#define _FORMFILE_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file FormFile.h
* \brief Class representing a file submitted via an HTML form.
*
* FormFile is an immutable class reprenting a file uploaded via
* the HTTP file upload mechanism. If you are going to use file upload
* in your CGI application, remember to set the ENCTYPE of the form to
* \c multipart/form-data.
*/
#include <iostream>
#include <string>
#include "CgiDefs.h"
namespace cgicc {
// ============================================================
// Class FormFile
// ============================================================
/*! \class FormFile FormFile.h cgicc/FormFile.h
* \brief Class representing a file submitted via an HTML form.
*
* FormFile is an immutable class reprenting a file uploaded via
* the HTTP file upload mechanism. If you are going to use file upload
* in your CGI application, remember to set the ENCTYPE of the form to
* \c multipart/form-data.
* \verbatim
<form method="post" action="http://change_this_path/cgi-bin/upload.cgi"
enctype="multipart/form-data">
\endverbatim
* \sa FormEntry
*/
class CGICC_API FormFile
{
public:
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Default constructor
*
* Shouldn't be used.
*/
inline
FormFile()
{}
/*!
* \brief Create a new FormFile.
*
* This is usually not called directly, but by Cgicc.
* \param name The \e name of the form element.
* \param filename The \e filename of the file on the remote machine.
* \param dataType The MIME content type of the data, if specified, or 0.
* \param data The file data.
*/
FormFile(const std::string& name,
const std::string& filename,
const std::string& dataType,
const std::string& data);
/*!
* \brief Copy constructor.
*
* Sets the name, filename, datatype, and data to those of \c file
* @param file The FormFile to copy.
*/
inline
FormFile(const FormFile& file)
{ operator=(file); }
/*!
* \brief Destructor
*
* Delete this FormFile object
*/
inline
~FormFile()
{}
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Compare two FormFiles for equality.
*
* FormFiles are equal if they have the same filename.
* @param file The FormFile to compare to this one.
* @return \c true if the two FormFiles are equal, \c false otherwise.
*/
bool
operator== (const FormFile& file) const;
/*!
* \brief Compare two FormFiles for inequality.
*
* FormFiles are equal if they have the same filename.
* \param file The FormFile to compare to this one.
* \return \c false if the two FormFiles are equal, \c true otherwise.
*/
inline bool
operator!= (const FormFile& file) const
{ return ! operator==(file); }
#ifdef WIN32
/* Dummy operator for MSVC++ */
inline bool
operator< (const FormFile& file) const
{ return false; }
#endif
/*!
* \brief Assign one FormFile to another.
*
* Sets the name, filename, datatype, and data to those of \c file
* \param file The FormFile to copy.
* \return A reference to this.
*/
FormFile&
operator= (const FormFile& file);
//@}
// ============================================================
/*! \name Accessor Methods
* Information on the uploaded file
*/
//@{
/*!
* \brief Write this file data to the specified stream.
*
* This is useful for saving uploaded data to disk
* \param out The ostream to which to write.
*/
void
writeToStream(std::ostream& out) const;
/*!
* \brief Get the name of the form element.
*
* The name of the form element is specified in the HTML form that
* called the CGI application.
* \return The name of the form element.
*/
inline std::string
getName() const
{ return fName; }
/*!
* \brief Get the basename of the file on the remote machine.
*
* The filename is stripped of all leading directory information
* \return The basename of the file on the remote machine.
*/
inline std::string
getFilename() const
{ return fFilename; }
/*!
* \brief Get the MIME type of the file data.
*
* This will be of the form \c text/plain or \c image/jpeg
* \return The MIME type of the file data.
*/
inline std::string
getDataType() const
{ return fDataType; }
/*!
* \brief Get the file data.
*
* This returns the raw file data as a string
* \return The file data.
*/
inline std::string
getData() const
{ return fData; }
/*!
* \brief Get the length of the file data
*
* The length of the file data is usually measured in bytes.
* \return The length of the file data, in bytes.
*/
inline std::string::size_type
getDataLength() const
{ return fData.length(); }
//@}
private:
std::string fName;
std::string fFilename;
std::string fDataType;
std::string fData;
};
} // namespace cgicc
#endif /* ! _FORMFILE_H_ */

View File

@ -0,0 +1,114 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLAtomicElement.h,v 1.7 2007/07/02 18:48:18 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTMLATOMICELEMENT_H_
#define _HTMLATOMICELEMENT_H_ 1
/*! \file HTMLAtomicElement.h
* \brief Template class for concrete atomic HTMLElement subclasses
*
*/
#include <new>
#include "cgicc/HTMLElement.h"
namespace cgicc {
// ============================================================
// Template for concrete atomic HTML element classes
// ============================================================
/*! \class HTMLAtomicElement HTMLAtomicElement.h cgicc/HTMLAtomicElement.h
* \brief Template for concrete atomic HTMLElement subclasses
*
* An atomic HTML element is an element in which the opening and closing
* tags are combined. For example, in the HTML code
\verbatim
<meta link="made" href="mailto:sbooth@gnu.org" />
\endverbatim
* The \c meta tag is an atomic HTML element because the opening and closing
* tags appear together.
* \sa HTMLElement
* \sa HTMLBooleanElement
*/
template<class Tag>
class HTMLAtomicElement : public HTMLElement
{
public:
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Create a new empty atomic element.
*
*/
HTMLAtomicElement()
: HTMLElement(0, 0, 0, eAtomic)
{}
/*!
* \brief Create a new element, specifying the HTMLAttributes.
*
* \param attributes The HTMLAttributes contained within the element.
*/
HTMLAtomicElement(const HTMLAttributeList& attributes)
: HTMLElement(&attributes, 0, 0, eAtomic)
{}
/*!
* \brief Destructor
*
*/
virtual ~HTMLAtomicElement()
{}
//@}
/*!
* \brief Clone this element
*
* \return A newly-allocated copy of this element
*/
virtual inline HTMLElement*
clone() const
{ return new HTMLAtomicElement<Tag>(*this); }
/*!
* \brief Get the name of this element.
*
* For example, \c meta.
* \return The name of this element
*/
virtual inline const char*
getName() const
{ return Tag::getName(); }
};
} // namespace cgicc
#endif /* ! _HTMLATOMICELEMENT_H_ */

View File

@ -0,0 +1,77 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLAttribute.cpp,v 1.8 2014/04/23 20:55:04 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTMLAttribute.h"
#include "CgiUtils.h"
// ============================================================
// Class HTMLAttribute
// ============================================================
cgicc::HTMLAttribute::HTMLAttribute()
{}
cgicc::HTMLAttribute::HTMLAttribute(const std::string& name)
: fName(name),
fValue(name)
{}
cgicc::HTMLAttribute::HTMLAttribute(const std::string& name,
const std::string& value)
: fName(name),
fValue(value)
{}
cgicc::HTMLAttribute::HTMLAttribute(const HTMLAttribute& attribute)
: MStreamable(),
fName(attribute.fName),
fValue(attribute.fValue)
{}
cgicc::HTMLAttribute::~HTMLAttribute()
{}
bool
cgicc::HTMLAttribute::operator== (const HTMLAttribute& att) const
{
return (stringsAreEqual(fName, att.fName)
&& stringsAreEqual(fValue, att.fValue));
}
cgicc::HTMLAttribute&
cgicc::HTMLAttribute::operator= (const HTMLAttribute& att)
{
fName = att.fName;
fValue = att.fValue;
return *this;
}
void
cgicc::HTMLAttribute::render(std::ostream& out) const
{
out << getName() << "=\"" << getValue() << "\"";
}

View File

@ -0,0 +1,237 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLAttribute.h,v 1.9 2014/04/23 20:55:04 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTMLATTRIBUTE_H_
#define _HTMLATTRIBUTE_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTMLAttribute.h
* \brief Class dealing with HTML element attributes
*
* For example, in the HTML code
\verbatim
<br clear="all" />
\endverbatim
* \c clear is an attribute of the \c br element.
*/
#include <string>
#include <iostream>
#include "CgiDefs.h"
#include "MStreamable.h"
namespace cgicc {
// ============================================================
// Class HTMLAttribute
// ============================================================
/*! \class HTMLAttribute HTMLAttribute.h cgicc/HTMLAttribute.h
* \brief Class representing a name or a single name/value pair
*
* An HTMLAttribute represents a single name/value
* pair inside an HTMLElement. For example, in the HTML code:
\verbatim
<a href="mailto:sbooth@gnu.org">Send mail</a>
\endverbatim
* The (name, value) pair <tt>(href, mailto:%sbooth@gnu.org)</tt> is
* an HTMLAttribute.
* HTMLAttribute objects are usually not created directly, but
* using the set() methods. To generate the HTML above using
* %cgicc, write
* \code
* cout << cgicc::a("Send Mail").set("href", "mailto:sbooth@gnu.org");
* \endcode
* \sa HTMLAttributeList
*/
class CGICC_API HTMLAttribute : public MStreamable
{
public:
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Create an empty HTMLAttribute.
*
* The name and value are set to an empty string.
*/
HTMLAttribute();
/*!
* \brief Create an HTMLAttribute with the given name.
*
* This will simply set the name and value to the same value.
* \param name The name of the attribute.
*/
HTMLAttribute(const std::string& name);
/*!
* \brief Create an HTMLAttribute with the given name and value.
*
* Most attributes are of this form
* \param name The attribute's name, for example \c href
* \param value The attributes's alue, for exampe \c foo.html
*/
HTMLAttribute(const std::string& name,
const std::string& value);
/*!
* \brief Copy constructor.
*
* Sets the name of value of this attribute to those of \c attribute
* \param attribute The HTMLAttribute to copy.
*/
HTMLAttribute(const HTMLAttribute& attribute);
/*!
* \brief Destructor
*
* Delete this HTMLAttribute object
*/
virtual ~HTMLAttribute();
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Compare two HTMLAttributes for equality.
*
* HTMLAttributes are equal if they have the same name and value.
* \param att The HTMLAttribute to compare to this one.
* \return \c true if the two HTMLAttributes are equal, \c false otherwise.
*/
bool
operator== (const HTMLAttribute& att) const;
/*!
* \brief Compare two HTMLAttributes for inequality.
*
* HTMLAttributes are equal if they have the same name and value.
* \param att The HTMLAttribute to compare to this one.
* \return \c false if the two HTMLAttributes are equal, \c true otherwise.
*/
inline bool
operator!= (const HTMLAttribute& att) const
{ return ! operator==(att); }
#ifdef WIN32
/* Dummy operator for MSVC++ */
inline bool
operator< (const HTMLAttribute& att) const
{ return false; }
#endif
/*!
* \brief Assign one HTMLAttribute to another.
*
* Sets the name of value of this attribute to those of \c att
* \param att The HTMLAttribute to copy.
* \return A reference to this.
*/
HTMLAttribute&
operator= (const HTMLAttribute& att);
//@}
// ============================================================
/*! \name Accessor Methods
* Information on the attribute
*/
//@{
/*!
* \brief Get the name of this HTMLAttribute.
*
* For example, \c HREF
* \return The attribute's name.
*/
inline std::string
getName() const
{ return fName; }
/*!
* \brief Get the value of this HTMLAttribute.
*
* For example, \c http://www.gnu.org
* \return The attribute's value.
*/
inline std::string
getValue() const
{ return fValue; }
//@}
// ============================================================
/*! \name Mutator Methods
* Set properties of the attribute
*/
//@{
/*!
* \brief Set the name of this HTMLAttribute.
*
* Use this method if the name wasn't specified in the constructor
* \param name The new name of the attribute.
*/
inline void
setName(const std::string& name)
{ fName = name; }
/*!
* \brief Set the value of this HTMLAttribute.
*
* Use this method if the value wasn't specified in the constructor
* \param value The new value of the attribute.
*/
inline void
setValue(const std::string& value)
{ fValue = value; }
//@}
/*!
* \brief Render this attribute to an ostream
*
* This is used for output purposes
* \param out The ostream to which to write
*/
virtual void
render(std::ostream& out) const;
private:
std::string fName;
std::string fValue;
};
} // namespace cgicc
#endif /* ! _HTMLATTRIBUTE_H_ */

View File

@ -0,0 +1,82 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLAttributeList.cpp,v 1.8 2014/04/23 20:55:05 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTMLAttributeList.h"
#include "CgiUtils.h"
// ============================================================
// Class HTMLAttributeList
// ============================================================
cgicc::HTMLAttributeList::HTMLAttributeList()
{
fAttributes.reserve(5);
}
cgicc::HTMLAttributeList::HTMLAttributeList(const HTMLAttribute& head)
{
fAttributes.reserve(5);
fAttributes.push_back(head);
}
cgicc::HTMLAttributeList::HTMLAttributeList(const HTMLAttributeList& list)
{
this->operator=(list);
}
cgicc::HTMLAttributeList::~HTMLAttributeList()
{}
cgicc::HTMLAttributeList&
cgicc::HTMLAttributeList::operator= (const HTMLAttributeList& list)
{
fAttributes = list.fAttributes;
return *this;
}
cgicc::HTMLAttributeList&
cgicc::HTMLAttributeList::set(const std::string& name)
{
fAttributes.push_back(HTMLAttribute(name));
return *this;
}
cgicc::HTMLAttributeList&
cgicc::HTMLAttributeList::set(const std::string& name,
const std::string& value)
{
fAttributes.push_back(HTMLAttribute(name, value));
return *this;
}
void
cgicc::HTMLAttributeList::render(std::ostream& out) const
{
std::vector<HTMLAttribute>::const_iterator iter;
for(iter = fAttributes.begin(); iter != fAttributes.end(); ++iter) {
out << *iter << ' ';
}
}

View File

@ -0,0 +1,211 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLAttributeList.h,v 1.8 2014/04/23 20:55:05 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTMLATTRIBUTELIST_H_
#define _HTMLATTRIBUTELIST_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTMLAttributeList.h
* \brief Class containing a list of HTMLAttribute objects
*
* The list is expandable and uses the STL vector class for storage
*/
#include <string>
#include <iostream>
#include <vector>
#include "CgiDefs.h"
#include "MStreamable.h"
#include "HTMLAttribute.h"
namespace cgicc {
// ============================================================
// Class HTMLAttributeList
// ============================================================
#ifdef WIN32
template class CGICC_API std::vector<HTMLAttribute>;
#endif
/*! \class HTMLAttributeList HTMLAttributeList.h cgicc/HTMLAttributeList.h
* \brief An expandable list of HTMLAttribute objects
*
* An HTMLAttributeList represents any number of HTMLAttribute objects
* which may be embedded in an HTMLElement. To add HTMLAttribute objects
* to an HTMLAttributeList, use the set() methods or functions.
* For example,
* \code
* cgicc::HTMLAttributeList list = cgicc::set("HEIGHT", "100").set("WIDTH", "100");
* \endcode
* generates an HTMLAttributeList with two elements.
* \see HTMLAttribute
* \see HTMLElement
*/
class CGICC_API HTMLAttributeList
{
public:
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Create an empty HTMLAttributeList.
*
* HTMLAttributeLists are most often created with the set functions
*/
HTMLAttributeList();
/*!
* \brief Create a new HTMLAttributeList, specifying the first element.
*
* The first attribute in the list is set to \c head
* \param head The first element of the list
*/
HTMLAttributeList(const HTMLAttribute& head);
/*!
* \brief Copy constructor.
*
* Sets the elements in this list to those in \c list
* \param list The HTMLAttributeList to copy.
*/
HTMLAttributeList(const HTMLAttributeList& list);
/*!
* \brief Destructor
*
* Delete this HTMLAttributeList object
*/
~HTMLAttributeList();
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Assign one HTMLAttributeList to another.
*
* Sets the elements in this list to those in \c list
* \param list The HTMLAttributeList to copy
*/
HTMLAttributeList&
operator= (const HTMLAttributeList &list);
//@}
// ============================================================
/*! \name List Management
* Add attributes to the list
*/
//@{
/*!
* \brief Add an atomic HTMLAttribute to this list
*
* \c isindex is an example of an atomic attribute.
* \param name The name of the HTMLAttribute to set.
* \return A reference to \c this
*/
HTMLAttributeList&
set(const std::string& name);
/*!
* \brief Add a HTMLAttribute to this list
*
* For a list of possible attributes see http://www.w3.org/TR/REC-html40/
* \param name The name of the HTMLAttribute to set.
* \param value The value of the HTMLAttribute to set.
* \return A reference to \c this
*/
HTMLAttributeList&
set(const std::string& name,
const std::string& value);
//@}
/*! \name Utility Methods */
//@{
/*!
* \brief Render this HTMLAttributeList to an ostream
*
* This is used for output
* \param out The ostream to which to write
*/
void
render(std::ostream& out) const;
//@}
private:
std::vector<HTMLAttribute> fAttributes;
};
// ============================================================
// List manipulators
// ============================================================
/*!
* \brief Create a new HTMLAttributeList, and set an HTMLAttribute.
*
* This function is usually called from within the constructor of an
* HTMLElement:
* \code
* out << img(set("ISINDEX")) << endl;
* \endcode
* \param name The name of the HTMLAttribute to set.
* \return A reference to the list.
*/
inline HTMLAttributeList
set(const std::string& name)
{ return HTMLAttributeList(HTMLAttribute(name)); }
/*!
* \brief Create a new HTMLAttributeList, and set an HTMLAttribute.
*
* This function is usually called from within the constructor of an
* HTMLElement:
* \code
* out << a("link text", set("HREF","http://www.foo.com")) << endl;
* \endcode
* \param name The name of the HTMLAttribute to set.
* \param value The value of the HTMLAttribute to set.
* \return A reference to the list.
*/
inline HTMLAttributeList
set(const std::string& name,
const std::string& value)
{ return HTMLAttributeList(HTMLAttribute(name, value)); }
} // namespace cgicc
#endif /* ! _HTMLATTRIBUTES_H_ */

View File

@ -0,0 +1,193 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLBooleanElement.h,v 1.9 2014/04/23 20:55:05 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTMLBOOLEANELEMENT_H_
#define _HTMLBOOLEANELEMENT_H_ 1
/*! \file HTMLBooleanElement.h
* \brief Template class for concrete boolean HTMLElement subclasses
*
*/
#include <new>
#include "HTMLElement.h"
namespace cgicc {
// ============================================================
// Template for concrete boolean HTML element classes
// ============================================================
/*! \class HTMLBooleanElement HTMLBooleanElement.h cgicc/HTMLBooleanElement.h
* \brief Template for concrete boolean HTMLElement subclasses
*
* A boolean HTML element is an element having a boolean (open or closed)
* state. Most commonly used HTML tags are boolean elements:
\verbatim
<a href="http://www.gnu.org">GNU Project</a>
\endverbatim
* The \c a element is boolean, since it is either open or closed. Boolean
* elements are often additive:
\verbatim
<b>bold text<i>bold italic text</i></b>
\endverbatim
* Note than under the XHTML 1.0 standard, elements may not overlap; ie,
* in the example above, it would be illegal to close the \c b tag before
* the \c i tag.
* \sa HTMLElement
* \sa HTMLAtomicElement
*/
template<class Tag>
class HTMLBooleanElement : public HTMLElement
{
public:
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Create a new empty boolean element.
*
*/
HTMLBooleanElement()
: HTMLElement(0, 0, 0, eBoolean)
{}
/*!
* \brief Create a new element, specifying the enclosed text.
* \param text The text within the element.
*/
HTMLBooleanElement(const std::string& text)
: HTMLElement(0, 0, &text, eBoolean)
{}
/*!
* \brief Create a new element, specifying the HTMLAttribute objects.
* \param attributes The HTMLAttributes contained within the element.
*/
HTMLBooleanElement(const HTMLAttributeList& attributes)
: HTMLElement(&attributes, 0, 0, eBoolean)
{}
/*!
* \brief Create a new element, specifying an embedded HTMLElement.
* \param embedded The HTMLElement embedded inside the element.
*/
HTMLBooleanElement(const HTMLElement& embedded)
: HTMLElement(0, &embedded, 0, eBoolean)
{}
/*!
* \brief Create a new element, specifying the enclosed text and
* HTMLAttribute objects.
* \param attributes The HTMLAttributes contained within the element.
* \param text The text within the element.
*/
HTMLBooleanElement(const std::string& text,
const HTMLAttributeList& attributes)
: HTMLElement(&attributes, 0, &text, eBoolean)
{}
/*!
* \brief Create a new element, specifying the HTMLAttributes and embedded
* HTMLElement.
* \param attributes The HTMLAttributes contained within the element.
* \param embed The HTMLElement embedded inside the element.
*/
HTMLBooleanElement(const HTMLAttributeList& attributes,
const HTMLElement& embed)
: HTMLElement(&attributes, &embed, 0, eBoolean)
{}
/*!
* \brief Destructor
*
*/
virtual ~HTMLBooleanElement()
{}
//@}
// ============================================================
/*!
* \brief Clone this element
* \return A newly-allocated copy of this element
*/
virtual inline HTMLElement*
clone() const
{ return new HTMLBooleanElement<Tag>(*this); }
// ============================================================
/*!
* \brief Get the name of this element. For example, "strong"
* \return The name of this element
*/
virtual inline const char*
getName() const
{ return Tag::getName(); }
// ============================================================
/*! \name State Management */
//@{
/*!
* \brief Swap the state of this boolean element
*
* A state of \c true indicates the element is currently open
*/
virtual inline void
swapState() const
{ sState = ! sState; }
/*!
* \brief Get the state of this boolean element
* \return \c true if this element is open, \c false otherwise
*/
virtual inline bool
getState() const
{ return sState; }
/*!
* \brief Reset the state of this boolean element to closed
*
*/
static inline void
reset()
{ sState = false; }
//@}
private:
static bool sState;
};
template<class Tag>
bool cgicc::HTMLBooleanElement<Tag>::sState = false;
} // namespace cgicc
#endif /* ! _HTMLBOOLEANELEMENT_H_ */

View File

@ -0,0 +1,216 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLClasses.h,v 1.17 2014/04/23 20:55:05 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTMLCLASSES_H_
#define _HTMLCLASSES_H_ 1
/*! \file HTMLClasses.h
* \brief The header file containing HTML output classes.
*
* One class is defined for each element in the HTML 4.0 standard.
*/
#include "CgiDefs.h"
#include "HTMLAtomicElement.h"
#include "HTMLBooleanElement.h"
#include "HTMLDoctype.h"
// ============================================================
// Macros defining types of elements
// ============================================================
/*!
* \brief Create an HTML element rendering class
*
* \param name The name of the class to define
* \param tag The text to output when this tag is rendered
*/
#define TAG(name, tag) \
class name##Tag \
{ public: inline static const char* getName() { return tag; } }
/*!
* \brief Create an atomic HTML element
*
* Atomic HTML elements maintain no internal on/off state. For
* example, \c br and \c meta are atomic elements.
* \param name The name of the class to define
* \param tag The text to output when this tag is rendered
*/
#define ATOMIC_ELEMENT(name, tag) \
TAG(name, tag); typedef HTMLAtomicElement<name##Tag> name
/*!
* \brief An HTML element maintaining an internal on/off state
*
* Boolean HTML elements maintain an internal state, and the output
* rendered depends on the current state. For example, \c h1 and \c
* title are boolean elements.
* \param name The name of the class to define
* \param tag The text to output when this tag is rendered
*/
#define BOOLEAN_ELEMENT(name, tag) \
TAG(name, tag); typedef HTMLBooleanElement<name##Tag> name
// ============================================================
// HTML 4.0 elements - for details see http://www.w3.org/
// ============================================================
namespace cgicc {
// ============================================================
// Class comment - needs special render function
// ============================================================
class nullTag
{ public: inline static const char* getName() { return 0; } };
/*! \class comment HTMLClasses.h cgicc/HTMLClasses.h
* \brief An HTML comment
*/
class comment : public HTMLBooleanElement<nullTag>
{
virtual void render(std::ostream& out) const
{
if(getData().empty() && false == dataSpecified()) {
swapState();
out << (getState() ? "<!-- " : " -->");
}
else
out << "<!-- " << getData() << " -->";
}
};
BOOLEAN_ELEMENT (html, "html"); // HTML document
BOOLEAN_ELEMENT (head, "head"); // document head
BOOLEAN_ELEMENT (title, "title"); // document title
ATOMIC_ELEMENT (meta, "meta"); // meta data
BOOLEAN_ELEMENT (style, "style"); // style sheet
BOOLEAN_ELEMENT (body, "body"); // document body
BOOLEAN_ELEMENT (div, "div"); // block-level grouping
BOOLEAN_ELEMENT (span, "span"); // inline grouping
BOOLEAN_ELEMENT (h1, "h1"); // level 1 heading
BOOLEAN_ELEMENT (h2, "h2"); // level 2 heading
BOOLEAN_ELEMENT (h3, "h3"); // level 3 heading
BOOLEAN_ELEMENT (h4, "h4"); // level 4 heading
BOOLEAN_ELEMENT (h5, "h5"); // level 5 heading
BOOLEAN_ELEMENT (h6, "h6"); // level 6 heading
BOOLEAN_ELEMENT (address, "address"); // contact information
// text markup
BOOLEAN_ELEMENT (em, "em"); // emphasis
BOOLEAN_ELEMENT (strong, "strong"); // stronger emphasis
BOOLEAN_ELEMENT (cite, "cite"); // citation/reference
BOOLEAN_ELEMENT (dfn, "dfn"); // defining instance
BOOLEAN_ELEMENT (code, "code"); // computer code
BOOLEAN_ELEMENT (samp, "samp"); // sample output
BOOLEAN_ELEMENT (kbd, "kbd"); // user input
BOOLEAN_ELEMENT (var, "var"); // variable/argument
BOOLEAN_ELEMENT (abbr, "abbr"); // abbreviated form
BOOLEAN_ELEMENT (acronym, "acronym"); // acronym
BOOLEAN_ELEMENT (blockquote, "blockquote"); // block-level quotation
BOOLEAN_ELEMENT (q, "q"); // inline quotation
BOOLEAN_ELEMENT (sub, "sub"); // subscript
BOOLEAN_ELEMENT (sup, "sup"); // superscript
BOOLEAN_ELEMENT (p, "p"); // paragraph
ATOMIC_ELEMENT (br, "br"); // line break
BOOLEAN_ELEMENT (pre, "pre"); // preformatted text
BOOLEAN_ELEMENT (ins, "ins"); // inserted text
BOOLEAN_ELEMENT (del, "del"); // deleted text
BOOLEAN_ELEMENT (bdo, "bdo"); // overriding direction
// lists
BOOLEAN_ELEMENT (ul, "ul"); // unordered list
BOOLEAN_ELEMENT (ol, "ol"); // ordered list
BOOLEAN_ELEMENT (li, "li"); // list item
BOOLEAN_ELEMENT (dl, "dl"); // definition list
BOOLEAN_ELEMENT (dt, "dt"); // term to be defined
BOOLEAN_ELEMENT (dd, "dd"); // definition of term
// tables
BOOLEAN_ELEMENT (table, "table"); // table element
BOOLEAN_ELEMENT (caption, "caption"); // table caption
BOOLEAN_ELEMENT (thead, "thead"); // table head section
BOOLEAN_ELEMENT (tfoot, "tfoot"); // table foot section
BOOLEAN_ELEMENT (tbody, "tbody"); // table body section
BOOLEAN_ELEMENT (colgroup, "colgroup"); // vertical section
ATOMIC_ELEMENT (col, "col"); // column attributes
BOOLEAN_ELEMENT (tr, "tr"); // table row
BOOLEAN_ELEMENT (th, "th"); // table header cell
BOOLEAN_ELEMENT (td, "td"); // table data cell
// links
BOOLEAN_ELEMENT (a, "a"); // anchor
ATOMIC_ELEMENT (link, "link"); // document link
ATOMIC_ELEMENT (base, "base"); // path information
// objects
ATOMIC_ELEMENT (img, "img"); // inline image
BOOLEAN_ELEMENT (object, "object"); // generic object
ATOMIC_ELEMENT (param, "param"); // object parameters
BOOLEAN_ELEMENT (map, "map"); // client image map
ATOMIC_ELEMENT (area, "area"); // image map region
ATOMIC_ELEMENT (hr, "hr"); // horizontal rule
// fonts - preferably use stylesheets
BOOLEAN_ELEMENT (tt, "tt"); // monospaced text
BOOLEAN_ELEMENT (i, "i"); // italic text style
BOOLEAN_ELEMENT (b, "b"); // bold text style
BOOLEAN_ELEMENT (big, "big"); // large font
BOOLEAN_ELEMENT (small, "small"); // small font
// frames - not part of the strict DTD
BOOLEAN_ELEMENT (frameset, "frameset"); // frame layout
ATOMIC_ELEMENT (frame, "frame"); // frame contents
BOOLEAN_ELEMENT (noframes, "noframes"); // alternative text
BOOLEAN_ELEMENT (iframe, "iframe"); // inline frame
// forms
BOOLEAN_ELEMENT (form, "form"); // form element
ATOMIC_ELEMENT (input, "input"); // generic input
BOOLEAN_ELEMENT (button, "button"); // special button
BOOLEAN_ELEMENT (select, "select"); // option menu
BOOLEAN_ELEMENT (optgroup, "optgroup"); // option group
BOOLEAN_ELEMENT (option, "option"); // option item
BOOLEAN_ELEMENT (textarea, "textarea"); // multi-line text input
BOOLEAN_ELEMENT (label, "label"); // input label
BOOLEAN_ELEMENT (fieldset, "fieldset"); // grouping input fields
BOOLEAN_ELEMENT (legend, "legend"); // caption for field set
// scripts
BOOLEAN_ELEMENT (script, "script"); // script element
BOOLEAN_ELEMENT (noscript, "noscript"); // alternative text
} // namespace cgicc
#endif /* ! _HTMLCLASSES_H_ */

View File

@ -0,0 +1,84 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLDoctype.cpp,v 1.9 2014/12/07 14:33:02 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
#pragma implementation
#endif
#include "HTMLDoctype.h"
// ============================================================
// Class HTMLDoctype
// ============================================================
cgicc::HTMLDoctype::HTMLDoctype(EDocumentType type)
: fType(type)
{}
cgicc::HTMLDoctype::~HTMLDoctype()
{}
void
cgicc::HTMLDoctype::render(std::ostream &out) const
{
bool bHTML5 = false;
out << "<!DOCTYPE HTML";
switch(fType) {
case eStrict:
break;
case eTransitional:
out << " PUBLIC \"-//W3C//DTD HTML 4.0 Transitional";
break;
case eFrames:
out << " PUBLIC \"-//W3C//DTD HTML 4.0 Frameset";
break;
case eHTML5:
bHTML5 = true;
break;
}
if(!bHTML5)
out << "//EN\" \"http://www.w3.org/TR/REC-html40/";
switch(fType) {
case eStrict:
out << "strict.dtd\"";
break;
case eTransitional:
out << "transitional.dtd\"";
break;
case eFrames:
out << "frameset.dtd\"";
break;
case eHTML5: // 11.30.14 t.o.
break;
}
out << '>';
}

View File

@ -0,0 +1,95 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLDoctype.h,v 1.10 2014/12/07 14:33:02 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTMLDOCTYPE_H_
#define _HTMLDOCTYPE_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTMLDoctype.h
* \brief Class which specifies the DTD of the HTML 4 document
*
*/
#include <string>
#include "MStreamable.h"
namespace cgicc {
// ============================================================
// Class HTMLDoctype
// ============================================================
/*! \class HTMLDoctype HTMLDoctype.h cgicc/HTMLDoctype.h
* \brief Specifies the DTD of the HTML 4 document
*
* To use this class, simply write an object of this type to an ostream:
* \code
* out << cgicc::HTMLDoctype();
* \endcode
* For more information, see \c http://www.w3.org/MarkUp/ and
* \c http://www.w3.org/TR/REC-html40/
*/
class CGICC_API HTMLDoctype : public MStreamable
{
public:
/*! The DTD used by this document. */
enum EDocumentType {
/*! The HTML 4.0 strict DTD (the default) */
eStrict,
/*! The HTML 4.0 Transitional DTD */
eTransitional,
/*! The HTML 4.0 Frameset DTD */
eFrames,
/*! HTML5 (added 11.30.14 t.o.) */
eHTML5
};
/*!
* \brief Constructor.
* \param type The version of the HTML 4.0 DTD used by this document.
*/
HTMLDoctype(EDocumentType type = eStrict);
/*!
* \brief Destructor
*
*/
virtual ~HTMLDoctype();
virtual void
render(std::ostream& out) const;
private:
EDocumentType fType;
};
} // namespace cgicc
#endif /* ! _HTMLDOCTYPE_H_ */

View File

@ -0,0 +1,212 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLElement.cpp,v 1.10 2014/04/23 20:55:05 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include <new>
#include <cstring>
#include "HTMLElement.h"
#include "HTMLElementList.h"
// ============================================================
// Class HTMLElement
// ============================================================
cgicc::HTMLElement::HTMLElement(const HTMLElement& element)
: MStreamable(),
fAttributes(0),
fEmbedded(0)
{
this->operator= (element);
}
cgicc::HTMLElement::HTMLElement(const HTMLAttributeList *attributes,
const HTMLElement *embedded,
const std::string *data,
EElementType type)
: fAttributes(0),
fEmbedded(0),
fData(),
fType(type),
fDataSpecified(false)
{
if(0 != attributes)
fAttributes = new HTMLAttributeList(*attributes);
if(0 != embedded)
fEmbedded = new HTMLElementList(*embedded);
if(0 != data) {
fData = *data;
fDataSpecified = true;
}
}
cgicc::HTMLElement::~HTMLElement()
{
delete fAttributes;
delete fEmbedded;
}
bool
cgicc::HTMLElement::operator== (const HTMLElement& element) const
{
// this is really lame, but only necessary for template instantiation
return (strcmp(getName(), element.getName()) == 0
&& fDataSpecified == element.fDataSpecified);
}
cgicc::HTMLElement&
cgicc::HTMLElement::operator= (const HTMLElement& element)
{
// avoid memory leak; bug fix from Francois Degros
delete fAttributes;
delete fEmbedded;
fAttributes = element.fAttributes;
fEmbedded = element.fEmbedded;
fData = element.fData;
fType = element.fType;
fDataSpecified = element.fDataSpecified;
// perform a deep copy
if(0 != fAttributes)
fAttributes = new HTMLAttributeList(*fAttributes);
if(0 != fEmbedded)
fEmbedded = new HTMLElementList(*fEmbedded);
return *this;
}
void
cgicc::HTMLElement::setAttributes(const HTMLAttributeList& attributes)
{
delete fAttributes;
fAttributes = new HTMLAttributeList(attributes);
}
void
cgicc::HTMLElement::setEmbedded(const HTMLElementList& embedded)
{
delete fEmbedded;
fEmbedded = new HTMLElementList(embedded);
}
cgicc::HTMLElement&
cgicc::HTMLElement::add(const HTMLElement& element)
{
if(0 == fEmbedded)
fEmbedded = new HTMLElementList();
fEmbedded->add(element);
return *this;
}
cgicc::HTMLElement&
cgicc::HTMLElement::add(HTMLElement *element)
{
if(0 == fEmbedded)
fEmbedded = new HTMLElementList();
fEmbedded->add(element);
return *this;
}
cgicc::HTMLElement&
cgicc::HTMLElement::set(const std::string& name)
{
if(0 == fAttributes)
fAttributes = new HTMLAttributeList();
fAttributes->set(name);
return *this;
}
cgicc:: HTMLElement&
cgicc::HTMLElement::set(const std::string& name,
const std::string& value)
{
if(0 == fAttributes)
fAttributes = new HTMLAttributeList();
fAttributes->set(name, value);
return *this;
}
void
cgicc::HTMLElement::render(std::ostream& out) const
{
if(eBoolean == getType() && false == dataSpecified()) {
/* no embedded elements */
if(0 == fEmbedded) {
swapState();
/* getState() == true ===> element is active */
if(true == getState()) {
out << '<' << getName();
/* render attributes, if present */
if(0 != fAttributes) {
out << ' ';
fAttributes->render(out);
}
out << '>';
}
else
out << "</" << getName() << '>';
}
/* embedded elements present */
else {
out << '<' << getName();
/* render attributes, if present */
if(0 != fAttributes) {
out << ' ';
fAttributes->render(out);
}
out << '>';
fEmbedded->render(out);
out << "</" << getName() << '>';
}
}
/* For non-boolean elements */
else {
if(eAtomic == getType()) {
out << '<' << getName();
if(0 != fAttributes) {
out << ' ';
fAttributes->render(out);
}
out << " />";
}
else {
out << '<' << getName();
if(0 != fAttributes) {
out << ' ';
fAttributes->render(out);
}
out << '>';
if(0 != fEmbedded)
fEmbedded->render(out);
else
out << getData();
out << "</" << getName() << '>';
}
}
}

View File

@ -0,0 +1,382 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLElement.h,v 1.9 2014/04/23 20:55:06 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTMLELEMENT_H_
#define _HTMLELEMENT_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTMLElement.h
* \brief Class dealing with HTML elements
*
* For example, \c a, \c img, \c html, and \c body, are all HTML elements.
*/
#include <string>
#include "CgiDefs.h"
#include "MStreamable.h"
#include "HTMLAttributeList.h"
namespace cgicc {
class HTMLElementList;
// ============================================================
// Class HTMLElement
// ============================================================
/*! \class HTMLElement HTMLElement.h cgicc/HTMLElement.h
* \brief Class representing an HTML element.
*
* An HTML element is any entity enclosed in angle brackets (\< and \>)
* interpreted as HTML, for example \c a, \c img, \c html, and \c body.
*
* This class is an abstract base class that defines the interface
* for all HTMLElement subclasses.
*/
class CGICC_API HTMLElement : public MStreamable
{
public:
/*!
* \brief Possible types of HTMLElements
*
* An HTMLElement is either atomic, meaning it has no corresponding
* closing tag (elements such as \c hr and \c br are atomic) or
* boolean (elements such as \c a and \c ol are boolean)
*/
enum EElementType {
/*! Atomic element, such as \c hr */
eAtomic,
/*! Boolean element, such as \c strong */
eBoolean
};
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Copy constructor.
*
* Sets the name and internal state of this element to those of \c element
* \param element The HTMLElement to copy.
*/
HTMLElement(const HTMLElement& element);
/*!
* \brief Destructor
*
* Delete this HTMLElement object
*/
virtual ~HTMLElement();
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Compare two HTMLElements for equality.
*
* HTMLElements are equal if they have the same name
* \param element The HTMLElement to compare to this one.
* \return \c true if the two HTMLElements are equal, \c false otherwise.
*/
bool
operator== (const HTMLElement& element) const;
/*!
* \brief Compare two HTMLElements for inequality.
*
* HTMLElements are equal if they have the same name
* \param element The HTMLElement to compare to this one.
* \return \c false if the two HTMLElements are equal, \c true otherwise.
*/
inline bool
operator!= (const HTMLElement& element) const
{ return ! operator==(element); }
#ifdef WIN32
/* Dummy operator for MSVC++ */
inline bool
operator< (const HTMLElement& element) const
{ return false; }
#endif
/*!
* \brief Assignment operator
*
* Sets the name and internal state of this element to those of \c element
* \param element The HTMLElement to copy
* \return A reference to \c this
*/
HTMLElement&
operator= (const HTMLElement& element);
//@}
// ============================================================
/*! \name Accessor Methods
* Information on the element
*/
//@{
/*!
* \brief Get the name of this element.
*
* For example, \c html or \c body.
* \return The name of this element.
*/
virtual const char*
getName() const = 0;
/*!
* \brief Get the data contained in this element, if any.
*
* This is only applicable for boolean elements
* \return The data contained in this element.
*/
inline std::string
getData() const
{ return fData; }
/*!
* \brief Get the type of this element
*
* Most HTMLElements are boolean
* \return The type of this element
*/
inline EElementType
getType() const
{ return fType; }
//@}
// ============================================================
/*! \name Mutator Methods
* Set properties of the element
*/
//@{
/*!
* \brief Set the data contained in this element.
*
* The data is the text contained between the opening and closing tags
* \param data The data to store in this element.
*/
inline void
setData(const std::string& data)
{ fData = data; }
//@}
// ============================================================
/*!
* \brief Clone this HTMLElement
*
* This performs a deep copy of the element
* \return A pointer to a newly-allocated copy of \c this.
*/
virtual HTMLElement*
clone() const = 0;
// ============================================================
/*! \name Embedded HTMLElement Management
* Manage elements embedded in this one
*/
//@{
/*!
* \brief Get the HTMLElementList embedded in this element, if any.
*
* If this method returns 0, no elements are embedded
* \return The embedded element list.
*/
inline const HTMLElementList*
getEmbedded() const
{ return fEmbedded; }
/*!
* \brief Set the HTMLElementList associated with this element.
*
* This is usually called by subclass constructors
* \param embedded The HTMLElementList containing the HTMLElements
* embedded in this element.
*/
void
setEmbedded(const HTMLElementList& embedded);
/*!
* \brief Add an embedded HTMLElement in this one
*
*
* \param element A reference to an HTMLElement to embed in this one
* \return A reference to \c this
*/
HTMLElement&
add(const HTMLElement& element);
/*!
* \brief Add an embedded HTMLElement in this one
*
* This element takes ownership of \c element, which should not be deleted.
* \param element A pointer to an HTMLElement to embed.
* \return A reference to \c this
*/
HTMLElement&
add(HTMLElement *element);
//@}
// ============================================================
/*! \name HTMLAttribute Management
* Manage attributes embedded in this element
*/
//@{
/*!
* \brief Get the attributes associated with this element.
*
* If this method returns 0, no attributes are embedded
* \return The attribute list.
*/
inline const HTMLAttributeList*
getAttributes() const
{ return fAttributes; }
/*!
* \brief Set the attributes associated with this element.
*
* This is usually called by subclass constructors
* \param attributes The HTMLAttributeList containing the HTMLAttributes
* belonging to this element.
*/
void
setAttributes(const HTMLAttributeList& attributes);
/*!
* \brief Set an HTMLAttribute on this HTMLElement
*
*
* \param name The name of the HTMLAttribute to set
* \return A reference to \c this
*/
HTMLElement&
set(const std::string& name);
/*!
* \brief Set an HTMLAttribute on this HTMLElement
*
*
* \param name The name of the HTMLAttribute
* \param value The value of the HTMLAttribute
* \return A reference to \c this
*/
HTMLElement&
set(const std::string& name,
const std::string& value);
//@}
// ============================================================
/*! \name Boolean element methods
* Methods specific to boolean elements
*/
//@{
/*!
* \brief Swap the state of the boolean element
*
* A state of \c true means the element is active
*/
virtual void
swapState() const
{}
/*!
* \brief Get the state of this boolean element
*
*
* \return \c true if the element is active, \c false otherwise
*/
virtual bool
getState() const
{ return false; }
//@}
/*!
* \brief Render this HTMLElement to an ostream
*
* This is used for output
* \param out The ostream to which to write
*/
virtual void
render(std::ostream& out) const;
protected:
/*!
* \brief Subclass constructor
*
* This allows the subclasses to fully specify all properties
* \param attributes A pointer to an HTMLAttributeList containing the
* HTMLAttributes for this HTMLElement, if any
* \param embedded A pointer to the embedded HTMLElement, if any
* \param data A pointer to the data, if any
* \param type The type of element
*/
HTMLElement(const HTMLAttributeList *attributes,
const HTMLElement *embedded,
const std::string *data,
EElementType type);
/*!
* \brief For subclasses only
*
* Returns \c true if data was specified in the constructor.
* \return \c true if data was specified in the constructor, \c false otherwise
*/
inline bool
dataSpecified() const
{ return fDataSpecified; }
private:
HTMLElement() {}
HTMLAttributeList *fAttributes;
HTMLElementList *fEmbedded;
std::string fData;
EElementType fType;
bool fDataSpecified;
};
} // namespace cgicc
#endif /* ! _HTMLELEMENT_H_ */

View File

@ -0,0 +1,91 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLElementList.cpp,v 1.8 2014/04/23 20:55:06 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include <new>
#include "HTMLElementList.h"
// ============================================================
// Class HTMLElementList
// ============================================================
cgicc::HTMLElementList::HTMLElementList()
{
fElements.reserve(5);
}
cgicc::HTMLElementList::HTMLElementList(const HTMLElement& head)
{
fElements.reserve(5);
fElements.push_back(head.clone());
}
cgicc::HTMLElementList::HTMLElementList(const HTMLElementList& list)
{
this->operator=(list);
}
cgicc::HTMLElementList::~HTMLElementList()
{
std::vector<HTMLElement*>::const_iterator iter;
for(iter = fElements.begin(); iter != fElements.end(); ++iter)
delete *iter;
}
cgicc::HTMLElementList&
cgicc::HTMLElementList::operator= (const HTMLElementList& list)
{
fElements = list.fElements;
std::vector<HTMLElement*>::iterator iter;
for(iter = fElements.begin(); iter != fElements.end(); ++iter)
*iter = (*iter)->clone();
return *this;
}
cgicc::HTMLElementList&
cgicc::HTMLElementList::add(const HTMLElement& element)
{
fElements.push_back(element.clone());
return *this;
}
cgicc::HTMLElementList&
cgicc::HTMLElementList::add(HTMLElement *element)
{
fElements.push_back(element);
return *this;
}
void
cgicc::HTMLElementList::render(std::ostream& out) const
{
std::vector<HTMLElement*>::const_iterator iter;
for(iter = fElements.begin(); iter != fElements.end(); ++iter)
(*iter)->render(out);
}

View File

@ -0,0 +1,168 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTMLElementList.h,v 1.9 2014/04/23 20:55:06 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTMLELEMENTLIST_H_
#define _HTMLELEMENTLIST_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTMLElementList.h
* \brief Class containing a list of HTMLElement objects
*
* The list is expandable and uses the STL vector class for storage
*/
#include <string>
#include <vector>
#include "CgiDefs.h"
#include "MStreamable.h"
#include "HTMLAttribute.h"
#include "HTMLElement.h"
namespace cgicc {
// ============================================================
// Class HTMLElementList
// ============================================================
#ifdef WIN32
template class CGICC_API std::vector<HTMLElement*>;
#endif
/*! \class HTMLElementList HTMLElementList.h cgicc/HTMLElementList.h
* \brief An expandable list of HTMLElement objects
*
* An HTMLElementList represents any number of HTMLElement objects.
* To add HTMLElement objects to the list, use the add() methods:
* \code
* cgicc::HTMLElementList list;
* list.add(br());
* \endcode
* \see HTMLAttribute
* \see HTMLElement
*/
class CGICC_API HTMLElementList
{
public:
// ============================================================
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Create an empty HTMLElementList.
*
* HTMLElementLists are most often created with the add() functions
*/
HTMLElementList();
/*!
* \brief Create a new HTMLElementList, specifying the first element.
*
* The first element in the list is set to \c head
* \param head The first element of the list
*/
HTMLElementList(const HTMLElement& head);
/*!
* \brief Copy constructor.
*
* Sets the elements in this list to those of \c list
* \param list The HTMLElementList to copy.
*/
HTMLElementList(const HTMLElementList& list);
/*!
* \brief Destructor
*
* Deletes this HTMLElementList object
*/
~HTMLElementList();
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Assignment operator
*
* Sets the elements in this list to those of \c list
* \param list The HTMLElementList to copy
* \return A reference to \c this
*/
HTMLElementList&
operator= (const HTMLElementList& list);
//@}
// ============================================================
/*! \name List Management
* Manage the elements in the list
*/
//@{
/*!
* \brief Add an HTMLElement to the list.
*
* \param element The HTMLElement to add.
* \return A reference to \c this
*/
HTMLElementList&
add(const HTMLElement& element);
/*!
* \brief Add an HTMLElement to the list.
*
* \param element The HTMLElement to add.
* \return A reference to the \c this
*/
HTMLElementList&
add(HTMLElement *element);
//@}
/*! Utility Methods */
//@{
/*!
* \brief Render this HTMLElementList
*
* \param out The ostream to which to write
*/
void
render(std::ostream& out) const;
//@}
private:
std::vector<HTMLElement*> fElements;
// elements must be stored as pointers, otherwise polymorphism doesn't work
};
} // namespace cgicc
#endif /* ! _HTMLELEMENTLIST_H_ */

View File

@ -0,0 +1,50 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPContentHeader.cpp,v 1.8 2014/04/23 20:55:06 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTTPContentHeader.h"
// ============================================================
// Class HTTPContentHeader
// ============================================================
cgicc::HTTPContentHeader::HTTPContentHeader(const std::string& mimeType)
: HTTPHeader(mimeType)
{}
cgicc::HTTPContentHeader::~HTTPContentHeader()
{}
void
cgicc::HTTPContentHeader::render(std::ostream& out) const
{
out << "Content-Type: " << getData() << std::endl;
std::vector<HTTPCookie>::const_iterator iter;
for(iter = getCookies().begin(); iter != getCookies().end(); ++iter)
out << *iter << std::endl;
out << std::endl;
}

View File

@ -0,0 +1,81 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPContentHeader.h,v 1.8 2014/04/23 20:55:06 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTTPCONTENTHEADER_H_
#define _HTTPCONTENTHEADER_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTTPContentHeader.h
* \brief Class for sending data of a specific MIME type
*
*/
#include <string>
#include "HTTPHeader.h"
namespace cgicc {
// ============================================================
// Class HTTPContentHeader
// ============================================================
/*! \class HTTPContentHeader HTTPContentHeader.h cgicc/HTTPContentHeader.h
* \brief HTTP header for data of a specified MIME type.
*
*/
class CGICC_API HTTPContentHeader : public HTTPHeader
{
public:
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Create a new MIME type header.
* \param mimeType The MIME type of the data which will be sent.
*/
HTTPContentHeader(const std::string& mimeType);
/*!
* \brief Destructor
*
*/
virtual ~HTTPContentHeader();
//@}
/*! \name Inherited Methods */
//@{
virtual void
render(std::ostream& out) const;
//@}
private:
HTTPContentHeader();
};
} // namespace cgicc
#endif /* ! _HTTPCONTENTHEADER_H_ */

View File

@ -0,0 +1,112 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPCookie.cpp,v 1.12 2014/04/23 20:55:07 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTTPCookie.h"
#include "CgiUtils.h"
// ============================================================
// Class HTTPCookie
// ============================================================
cgicc::HTTPCookie::HTTPCookie()
: fMaxAge(0),
fSecure(false),
fRemoved(false)
{}
cgicc::HTTPCookie::HTTPCookie(const std::string& name,
const std::string& value)
: fName(name),
fValue(value),
fMaxAge(0),
fSecure(false),
fRemoved(false)
{}
cgicc::HTTPCookie::HTTPCookie(const std::string& name,
const std::string& value,
const std::string& comment,
const std::string& domain,
unsigned long maxAge,
const std::string& path,
bool secure)
: fName(name),
fValue(value),
fComment(comment),
fDomain(domain),
fMaxAge(maxAge),
fPath(path),
fSecure(secure),
fRemoved(false)
{}
cgicc::HTTPCookie::HTTPCookie(const HTTPCookie& cookie)
: MStreamable(),
fName(cookie.fName),
fValue(cookie.fValue),
fComment(cookie.fComment),
fDomain(cookie.fDomain),
fMaxAge(cookie.fMaxAge),
fPath(cookie.fPath),
fSecure(cookie.fSecure),
fRemoved(cookie.fRemoved)
{}
cgicc::HTTPCookie::~HTTPCookie()
{}
bool
cgicc::HTTPCookie::operator== (const HTTPCookie& cookie) const
{
return (stringsAreEqual(fName, cookie.fName)
&& stringsAreEqual(fValue, cookie.fValue)
&& stringsAreEqual(fComment, cookie.fComment)
&& stringsAreEqual(fDomain, cookie.fDomain)
&& fMaxAge == cookie.fMaxAge
&& stringsAreEqual(fPath, cookie.fPath)
&& fSecure == cookie.fSecure
&& fRemoved == cookie.fRemoved);
}
void
cgicc::HTTPCookie::render(std::ostream& out) const
{
out << "Set-Cookie:" << fName << '=' << fValue;
if(false == fComment.empty())
out << "; Comment=" << fComment;
if(false == fDomain.empty())
out << "; Domain=" << fDomain;
if(fRemoved)
out << "; Expires=Fri, 01-Jan-1971 01:00:00 GMT;";
else if(0 != fMaxAge)
out << "; Max-Age=" << fMaxAge;
if(false == fPath.empty())
out << "; Path=" << fPath;
if(true == fSecure)
out << "; Secure";
out << "; Version=1";
}

View File

@ -0,0 +1,369 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPCookie.h,v 1.10 2014/04/23 20:55:07 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTTPCOOKIE_H_
#define _HTTPCOOKIE_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTTPCookie.h
* \brief An HTTP Cookie
*/
#include <string>
#include "MStreamable.h"
#include "CgiDefs.h"
namespace cgicc {
// ============================================================
// Class HTTPCookie
// ============================================================
/*! \class HTTPCookie HTTPCookie.h cgicc/HTTPCookie.h
* \brief An HTTP cookie
*
* An HTTP cookie is a way to maintain state between stateless HTTP
* requests. HTTP cookies consist of name/value pairs, with optional
* comments, domains, and expiration dates. Usually, you will add one
or more HTTPCookie objects to the HTTP headers your script is
* returning. For example, to set a cookie called \c count to \c 1 in
* a normal HTML document:
* \code
* out << HTTPHTMLHeader().setCookie(HTTPCookie("count","1"));
* \endcode
*/
class CGICC_API HTTPCookie : public MStreamable
{
public:
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Default Constructor
*
* Create a new, empty HTTPCookie.
*/
HTTPCookie();
/*!
* \brief Create a new HTTPCookie
*
* This is the most commonly-used constructor.
* \param name The name of the cookie.
* \param value The value of the cookie.
*/
HTTPCookie(const std::string& name,
const std::string& value);
/*!
* \brief Create a new fully-spefified HTTPCookie
*
*
* \param name The name of the cookie.
* \param value The value of the cookie.
* \param comment Any comment associated with the cookie.
* \param domain The domain for which this cookie is valid- an empty string
* will use the hostname of the server which generated the cookie response.
* If specified, the domain <em>must</em> start with a period('.').
* \param maxAge A number of seconds defining the lifetime of this cookie.
* A value of \c 0 indicates the cookie expires immediately.
* \param path The subset of URLS in a domain for which the cookie is
* valid, for example \c /
* @param secure Specifies whether this is a secure cookie.
*/
HTTPCookie(const std::string& name,
const std::string& value,
const std::string& comment,
const std::string& domain,
unsigned long maxAge,
const std::string& path,
bool secure);
/*!
* \brief Copy constructor
*
* Set the name, value, comment, domain, age and path of this cookie
* to those of \c cookie
* \param cookie The HTTPCookie to copy.
*/
HTTPCookie(const HTTPCookie& cookie);
/*!
* \brief Destructor
*
* Delete this HTTPCookie
*/
virtual ~HTTPCookie();
//@}
// ============================================================
/*! \name Overloaded Operators */
//@{
/*!
* \brief Compare two HTTPCookies for equality.
*
* Two HTTPCookie objects are equal if their names, values,
* comments, domains, ages, and paths match.
* \param cookie The HTTPCookie to compare to this one
* \return true if the two HTTPCookies are equal, false otherwise.
*/
bool
operator== (const HTTPCookie& cookie) const;
/*!
* \brief Compare two HTTPCookies for inequality.
*
* Two HTTPCookie objects are equal if their names, values,
* comments, domains, ages, and paths match.
* \param cookie The HTTPCookie to compare to this one
* \return false if the two HTTPCookies are equal, true otherwise.
*/
inline bool
operator != (const HTTPCookie& cookie) const
{ return ! operator==(cookie); }
#ifdef WIN32
/* Dummy operator for MSVC++ */
inline bool
operator< (const HTTPCookie& cookie) const
{ return false; }
#endif
//@}
// ============================================================
/*! \name Accessor Methods */
//@{
/*!
* \brief Mark this cookie as secure or unsecure.
*
*/
inline void
remove()
{ fRemoved = true; }
/*!
* \brief Mark this cookie as secure or unsecure.
*
* \param removed Set removed status
*/
inline void
setRemoved(bool removed)
{ fRemoved = removed; }
/*!
* \brief Determine if this is a removed cookie.
*
* \return True if this cookie is removed, false if not.
*/
inline bool
isRemoved() const
{ return fRemoved; }
/*!
* \brief Create a new partially-spefified HTTPCookie for deletion
*
*
* \param name The name of the cookie.
* \param domain The domain for which this cookie is valid- an empty string
* will use the hostname of the server which generated the cookie response.
* If specified, the domain <em>must</em> start with a period('.').
* \param path The subset of URLS in a domain for which the cookie is
* valid, for example \c /
* @param secure Specifies whether this is a secure cookie.
*/
HTTPCookie(const std::string& name,
const std::string& domain,
const std::string& path,
bool secure);
/*!
* \brief Get the name of this cookie.
*
* \return The name of this cookie.
*/
inline std::string
getName() const
{ return fName; }
/*!
* \brief Get the value of this cookie.
*
* \return The value of this cookie.
*/
inline std::string
getValue() const
{ return fValue; }
/*!
* \brief Get the comment of this cookie.
*
* \return The comment of this cookie.
*/
inline std::string
getComment() const
{ return fComment; }
/*!
* \brief Get the domain for which this cookie is valid.
*
* An empty string indicates the hostname of the server which
* generated the cookie response.
* \return The domain of this cookie, or "" if none.
*/
inline std::string
getDomain() const
{ return fDomain; }
/*!
* \brief Get the lifetime of this cookie, in seconds.
*
* \return The lifetime of this cookie, or 0 if none.
*/
inline unsigned long
getMaxAge() const
{ return fMaxAge; }
/*!
* \brief Get the path of this cookie.
*
* This is the subset of URLS in a domain for which the cookie is
* valid, for example \c /
* \return The path of this cookie, or "" if none.
*/
inline std::string
getPath() const
{ return fPath; }
/*!
* \brief Determine if this is a secure cookie.
*
* \return True if this cookie is secure, false if not.
*/
inline bool
isSecure() const
{ return fSecure; }
//@}
// ============================================================
/*! \name Mutator Methods */
//@{
/*!
* \brief Set the name of this cookie.
*
* \param name The name of this cookie.
*/
inline void
setName(const std::string& name)
{ fName = name; }
/*!
* \brief Set the value of this cookie.
*
* \param value The value of this cookie.
*/
inline void
setValue(const std::string& value)
{ fValue = value; }
/*!
* \brief Set the comment of this cookie.
*
* \param comment The comment of this cookie.
*/
inline void
setComment(const std::string& comment)
{ fComment = comment; }
/*!
* \brief Set the domain of this cookie.
*
* An empty string indicates the hostname of the server which
* generated the cookie response. If specified, the domain
* <em>must</em> start with a period('.').
* \param domain The domain of this cookie.
*/
inline void
setDomain(const std::string& domain)
{ fDomain = domain; }
/*!
* \brief Set the lifetime of this cookie, in seconds.
*
* A value of \c 0 indicated the cookie expires immediately
* \param maxAge The lifetime of this cookie, in seconds.
*/
inline void
setMaxAge(unsigned long maxAge)
{ fMaxAge = maxAge; }
/*!
* \brief Set the path of this cookie.
*
* This is the subset of URLS in a domain for which the cookie is
* valid, for example \c /
* \param path The path of this cookie.
*/
inline void
setPath(const std::string& path)
{ fPath = path; }
/*!
* \brief Mark this cookie as secure or unsecure.
*
* \param secure Whether this is a secure cookie.
*/
inline void
setSecure(bool secure)
{ fSecure = secure; }
//@}
// ============================================================
/*! \name Inherited Methods */
//@{
virtual void
render(std::ostream& out) const;
//@}
private:
std::string fName;
std::string fValue;
std::string fComment;
std::string fDomain;
unsigned long fMaxAge;
std::string fPath;
bool fSecure;
bool fRemoved;
};
} // namespace cgicc
#endif /* ! _HTTPCOOKIE_H_ */

View File

@ -0,0 +1,38 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPHTMLHeader.cpp,v 1.8 2014/04/23 20:55:07 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTTPHTMLHeader.h"
// ============================================================
// Class HTTPHTMLHeader
// ============================================================
cgicc::HTTPHTMLHeader::HTTPHTMLHeader()
: HTTPContentHeader("text/html")
{}
cgicc::HTTPHTMLHeader::~HTTPHTMLHeader()
{}

View File

@ -0,0 +1,70 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPHTMLHeader.h,v 1.8 2014/04/23 20:55:08 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTTPHTMLHEADER_H_
#define _HTTPHTMLHEADER_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTTPHTMLHeader.h
* \brief Shortcut to HTTPContentHeader for \c text/html
*
*/
#include "HTTPContentHeader.h"
namespace cgicc {
// ============================================================
// Class HTTPHTMLHeader
// ============================================================
/*! \class HTTPHTMLHeader HTTPHTMLHeader.h cgicc/HTTPHTMLHeader.h
* \brief Shortcut to HTTPContentHeader for \c text/html
*
*/
class CGICC_API HTTPHTMLHeader : public HTTPContentHeader
{
public:
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Create a new \c text/html header
*
*/
HTTPHTMLHeader();
/*!
* \brief Destructor
*
*/
virtual ~HTTPHTMLHeader();
//@}
};
} // namespace cgicc
#endif /* ! _HTTPHTMLHEADER_H_ */

View File

@ -0,0 +1,51 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPHeader.cpp,v 1.8 2014/04/23 20:55:08 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTTPHeader.h"
// ============================================================
// Class HTTPHeader
// ============================================================
cgicc::HTTPHeader::HTTPHeader()
{
fCookies.reserve(5);
}
cgicc::HTTPHeader::HTTPHeader(const std::string& data)
: fData(data)
{
fCookies.reserve(5);
}
cgicc::HTTPHeader::HTTPHeader(const HTTPHeader& header)
: MStreamable(),
fData(header.getData()),
fCookies(header.getCookies())
{}
cgicc::HTTPHeader::~HTTPHeader()
{}

View File

@ -0,0 +1,138 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPHeader.h,v 1.10 2014/04/23 20:55:08 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTTPHEADER_H_
#define _HTTPHEADER_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTTPHeader.h
* \brief Abstract base class for simple HTTP headers
*
*/
#include <string>
#include <vector>
#include "MStreamable.h"
#include "HTTPCookie.h"
namespace cgicc {
// ============================================================
// Class HTTPHeader
// ============================================================
/*! \class HTTPHeader HTTPHeader.h cgicc/HTTPHeader.h
* \brief Abstract base class for all simple HTTP response headers.
*
*/
class CGICC_API HTTPHeader : public MStreamable
{
public:
/*! \name Constructors and Destructor */
//@{
/*!
* \brief Constructor.
* \param data The header data.
*/
HTTPHeader(const std::string& data);
/*!
* \brief Copy constructor.
* \param header The HTTPHeader to copy.
*/
HTTPHeader(const HTTPHeader& header);
/*!
* \brief Destructor
*
*/
virtual ~HTTPHeader();
//@}
// ============================================================
/*! \name Cookie Management */
//@{
/*!
* \brief Set a cookie to go out with this HTTPResponseHeader
* \param cookie The HTTPCookie to set
*/
inline HTTPHeader&
setCookie(const HTTPCookie& cookie)
{ fCookies.push_back(cookie); return *this; }
/*!
* \brief Get a list of all cookies associated with this header
* \return All the cookies associated with this header
*/
inline const std::vector<HTTPCookie>&
getCookies() const
{ return fCookies; }
//@}
// ============================================================
/*! \name Accessor Method */
//@{
/*!
* Get the data contained in this HTTP header.
* @return The data contained in this header.
*/
inline std::string
getData() const
{ return fData; }
//@}
// ============================================================
/*! \name Subclass Methods */
//@{
/*!
* \brief Write this HTTPHeader to a stream.
*
* Subclasses must implement this function.
* \param out The ostream to which to write.
*/
virtual void
render(std::ostream& out) const = 0;
//@}
private:
HTTPHeader();
std::string fData;
std::vector<HTTPCookie> fCookies;
};
} // namespace cgicc
#endif /* ! _HTTPHEADER_H_ */

View File

@ -0,0 +1,38 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPPlainHeader.cpp,v 1.8 2014/04/23 20:55:08 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTTPPlainHeader.h"
// ============================================================
// Class HTTPPlainHeader
// ============================================================
cgicc::HTTPPlainHeader::HTTPPlainHeader()
: HTTPContentHeader("text/plain")
{}
cgicc::HTTPPlainHeader::~HTTPPlainHeader()
{}

View File

@ -0,0 +1,59 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPPlainHeader.h,v 1.8 2014/04/23 20:55:08 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTTPPLAINHEADER_H_
#define _HTTPPLAINHEADER_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTTPPlainHeader.h
* \brief Shortcut to HTTPContentHeader for \c text/plain
*
*/
#include "HTTPContentHeader.h"
namespace cgicc {
// ============================================================
// Class HTTPPlainHeader
// ============================================================
/*! \class HTTPPlainHeader HTTPPlainHeader.h cgicc/HTTPPlainHeader.h
* \brief Shortcut to HTTPContentHeader for \c text/html
*
*/
class CGICC_API HTTPPlainHeader : public HTTPContentHeader
{
public:
/*! \brief Create a new \c text/plain header */
HTTPPlainHeader();
/*! \brief Destructor */
virtual ~HTTPPlainHeader();
};
} // namespace cgicc
#endif /* ! _HTTPPLAINHEADER_H_ */

View File

@ -0,0 +1,63 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPRedirectHeader.cpp,v 1.10 2014/04/23 20:55:08 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTTPRedirectHeader.h"
// ============================================================
// Class HTTPRedirectHeader
// ============================================================
cgicc::HTTPRedirectHeader::HTTPRedirectHeader(const std::string& url)
: HTTPHeader(url) , fStatus(-1)
{}
cgicc::HTTPRedirectHeader::HTTPRedirectHeader(const std::string& url,bool permanent)
: HTTPHeader(url)
{
fStatus = permanent ? 301 : 302;
}
cgicc::HTTPRedirectHeader::~HTTPRedirectHeader()
{}
void
cgicc::HTTPRedirectHeader::render(std::ostream& out) const
{
if(fStatus == 301)
out << "Status: 301 Moved Permanently" << std::endl;
else if(fStatus == 302)
out << "Status: 302 Found" << std::endl;
out << "Location: " << getData() << std::endl;
if(false == getCookies().empty()) {
std::vector<HTTPCookie>::const_iterator iter;
for(iter = getCookies().begin(); iter != getCookies().end(); ++iter)
out << *iter << std::endl;
}
out << std::endl;
}

View File

@ -0,0 +1,91 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPRedirectHeader.h,v 1.9 2014/04/23 20:55:08 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTTPREDIRECTHEADER_H_
#define _HTTPREDIRECTHEADER_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTTPRedirectHeader.h
* \brief Class for redirecting the client to a different URI
*
*/
#include <string>
#include "HTTPHeader.h"
namespace cgicc {
// ============================================================
// Class HTTPRedirectHeader
// ============================================================
/*! \class HTTPRedirectHeader HTTPRedirectHeader.h cgicc/HTTPRedirectHeader.h
* \brief Class for redirecting the client to a different URI
*
*/
class CGICC_API HTTPRedirectHeader : public HTTPHeader
{
public:
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Create a new redirection header.
* \param url The redirection URL.
*/
HTTPRedirectHeader(const std::string& url);
/*!
* \brief Create a new redirection header with redirect status.
* \param url The redirection URL.
* \param permanent The status permanent or temporary
*/
HTTPRedirectHeader(const std::string& url,bool permanent);
/*!
* \brief Destructor
*
*/
virtual ~HTTPRedirectHeader();
//@}
// ============================================================
/*! \name Inherited Methods */
//@{
virtual void
render(std::ostream& out) const;
//@}
private:
HTTPRedirectHeader();
int fStatus;
};
} // namespace cgicc
#endif /* ! _HTTPREDIRECTHEADER_H_ */

View File

@ -0,0 +1,87 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPResponseHeader.cpp,v 1.9 2014/04/23 20:55:09 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTTPResponseHeader.h"
// ============================================================
// Class HTTPResponseHeader
// ============================================================
cgicc::HTTPResponseHeader::HTTPResponseHeader(const std::string& version,
int status_code,
const std::string& reason)
: MStreamable(),
fHTTPVersion(version),
fStatusCode(status_code),
fReasonPhrase(reason)
{
fHeaders.reserve(5);
}
cgicc::HTTPResponseHeader::~HTTPResponseHeader()
{}
cgicc::HTTPResponseHeader&
cgicc::HTTPResponseHeader::addHeader(const std::string& header)
{
fHeaders.push_back(header);
return *this;
}
cgicc::HTTPResponseHeader&
cgicc::HTTPResponseHeader::addHeader(const std::string& name,
const std::string& value)
{
fHeaders.push_back(name + ": " + value);
return *this;
}
cgicc::HTTPResponseHeader&
cgicc::HTTPResponseHeader::setCookie(const HTTPCookie& cookie)
{
fCookies.push_back(cookie);
return *this;
}
void
cgicc::HTTPResponseHeader::render(std::ostream& out) const
{
std::vector<std::string>::const_iterator iter;
std::vector<HTTPCookie>::const_iterator cookie_iter;
out << fHTTPVersion << ' ' << fStatusCode << ' ' << fReasonPhrase
<< std::endl;
for(iter = fHeaders.begin(); iter != fHeaders.end(); ++iter)
out << *iter << std::endl;
for(cookie_iter = getCookies().begin();
cookie_iter != getCookies().end();
++cookie_iter)
out << *cookie_iter << std::endl;
out << std::endl;
}

View File

@ -0,0 +1,250 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPResponseHeader.h,v 1.10 2014/04/23 20:55:09 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTTPRESPONSEHEADER_H_
#define _HTTPRESPONSEHEADER_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTTPResponseHeader.h
* \brief Class for generic, complete HTTP header responses
*
* This is an class usually only used with Non-Parsed Header (NPH)
* applications
*/
#include <string>
#include <vector>
#include "MStreamable.h"
#include "HTTPCookie.h"
namespace cgicc {
// ============================================================
// Class HTTPResponseHeader
// ============================================================
/*! \class HTTPResponseHeader HTTPResponseHeader.h cgicc/HTTPResponseHeader.h
* \brief Generic HTTP response header
*
* This class represents an HTTP response header as defined in
* section 6 of RFC 2616 (see http://www.w3.org)
*
* All HTTP/1.1 reponses consist of an initial status line containing
* the HTTP version, a 3-digit status code, and a human-readable reason
* phrase explaining the status code.
*
* The first digit of the Status-Code defines the class of
* response. The last two digits do not have any categorization
* role. There are 5 values for the first digit:
* <ul>
* <li>1xx: Informational - Request received, continuing process</li>
* <li>2xx: Success - The action was successfully received,
understood, and accepted</li>
* <li>3xx: Redirection - Further action must be taken in order to
* complete the request</li>
* <li>4xx: Client Error - The request contains bad syntax or cannot
* be fulfilled</li>
* <li>5xx: Server Error - The server failed to fulfill an apparently
* valid request</li></ul>
*/
class CGICC_API HTTPResponseHeader : public MStreamable
{
public:
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Create a new HTTP response header
* \param http_version The HTTP version string, usually \c HTTP/1.1
* \param status_code The 3-digit HTTP status code
* \param reason_phrase A short textual description of the status code
*/
HTTPResponseHeader(const std::string& http_version,
int status_code,
const std::string& reason_phrase);
/*!
* \brief Delete this HTTPResponseHeader
*
*/
virtual ~HTTPResponseHeader();
//@}
// ============================================================
/*! \name Additional Header Management */
//@{
/*!
* \brief Add a general, response, or entity header to this one
*
* \param header The text of the header to add
* \return A reference to this
*/
HTTPResponseHeader&
addHeader(const std::string& header);
/*!
* \brief Add a general, response, or entity header to this one
*
* \param name The name of the header element to add
* \param value The value of the header element
* \return A reference to this
*/
HTTPResponseHeader&
addHeader(const std::string& name,
const std::string& value);
/*!
* \brief Get a list of all additional headers
*
* \return A list of all additional headers
*/
inline const std::vector<std::string>&
getHeaders() const
{ return fHeaders; }
//@}
/*! \name Cookie Management */
//@{
/*!
* \brief Set a cookie to go out with this HTTPResponseHeader
* \param cookie The HTTPCookie to set
*/
HTTPResponseHeader&
setCookie(const HTTPCookie& cookie);
/*!
* \brief Get a list of all cookies associated with this header
* \return All the cookies associated with this header
*/
inline const std::vector<HTTPCookie>&
getCookies() const
{ return fCookies; }
//@}
// ============================================================
/*! \name Accessor methods
* Retrieve information on the header
*/
//@{
/*!
* \brief Get the HTTP version
*
* The HTTP version is a string of the form \c HTTP/1.1
* \return The HTTP version
*/
inline const std::string&
getHTTPVersion() const
{ return fHTTPVersion; }
/*!
* \brief Get the 3-digit status code
*
* The 3-digit status code indicates the disposition of the response.
* \return The 3-digit status code
*/
inline int
getStatusCode() const
{ return fStatusCode; }
/*!
* \brief Get the reason phrase associated with the stats code
*
* The reason phrase is a human-readable interpretation of the status code
* \return The reason phrase
*/
inline std::string
getReasonPhrase() const
{ return fReasonPhrase; }
//@}
// ============================================================
/*! \name Mutator methods
* Set information on the header
*/
//@{
/*!
* \brief Set the HTTP version
*
* The HTTP version is a string of the form \c HTTP/1.1
* \param http_version The HTTP version string, usually \c HTTP/1.1
* \return A reference to this
*/
inline HTTPResponseHeader&
getHTTPVersion(const std::string& http_version)
{ fHTTPVersion = http_version; return *this; }
/*!
* \brief Get the 3-digit status code
*
* The 3-digit status code indicates the disposition of the response.
* \param status_code The 3-digit HTTP status code
* \return A reference to this
*/
inline HTTPResponseHeader&
getStatusCode(int status_code)
{ fStatusCode = status_code; return *this; }
/*!
* \brief Get the reason phrase associated with the stats code
*
* The reason phrase is a human-readable interpretation of the status code
* \param reason_phrase A short textual description of the status code
* \return A reference to this
*/
inline HTTPResponseHeader&
getReasonPhrase(const std::string& reason_phrase)
{ fReasonPhrase = reason_phrase; return *this; }
//@}
// ============================================================
/*! \name Inherited Methods */
//@{
virtual void
render(std::ostream& out) const;
//@}
private:
HTTPResponseHeader();
std::string fHTTPVersion;
int fStatusCode;
std::string fReasonPhrase;
std::vector<std::string> fHeaders;
std::vector<HTTPCookie> fCookies;
};
} // namespace cgicc
#endif /* ! _HTTPRESPONSEHEADER_H_ */

View File

@ -0,0 +1,58 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPStatusHeader.cpp,v 1.8 2014/04/23 20:55:09 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "HTTPStatusHeader.h"
// ============================================================
// Class HTTPStatusHeader
// ============================================================
cgicc::HTTPStatusHeader::HTTPStatusHeader()
: HTTPHeader(""),
fStatus(-1)
{}
cgicc::HTTPStatusHeader::HTTPStatusHeader(int status,
const std::string& message)
: HTTPHeader(message),
fStatus(status)
{}
cgicc::HTTPStatusHeader::~HTTPStatusHeader()
{}
void
cgicc::HTTPStatusHeader::render(std::ostream& out) const
{
std::vector<HTTPCookie>::const_iterator iter;
out << "Status: " << getStatusCode() << ' ' << getData() << std::endl;
for(iter = getCookies().begin(); iter != getCookies().end(); ++iter)
out << *iter << std::endl;
out << std::endl;
}

View File

@ -0,0 +1,89 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPStatusHeader.h,v 1.8 2014/04/23 20:55:09 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _HTTPSTATUSHEADER_H_
#define _HTTPSTATUSHEADER_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file HTTPStatusHeader.h
* \brief HTTP header to set a specific request status
*
*/
#include <string>
#include "HTTPHeader.h"
namespace cgicc {
// ============================================================
// Class HTTPStatusHeader
// ============================================================
/*! \class HTTPStatusHeader HTTPStatusHeader.h cgicc/HTTPStatusHeader.h
* \brief HTTP header to set a specific request status
*
*/
class CGICC_API HTTPStatusHeader : public HTTPHeader
{
public:
/*!
* \brief Create a new status header.
* \param status The 3-digit status code, for example 404.
* \param message The message associated with the status code, for example
* "not found".
*/
HTTPStatusHeader(int status,
const std::string& message);
/*! \brief Destructor */
virtual ~HTTPStatusHeader();
/*!
* \brief Get the status code associated with this header.
* \return The 3-digit status code of this header.
*/
inline int
getStatusCode() const
{ return fStatus; }
/*!
* \brief Write this HTTPStatusHeader to a stream.
* \param out The ostream to which to write.
*/
virtual void
render(std::ostream& out) const;
private:
HTTPStatusHeader();
int fStatus;
};
} // namespace cgicc
#endif /* ! _HTTPSTATUSHEADER_H_ */

View File

@ -0,0 +1,30 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPXHTMLHeader.cpp,v 1.1 2008/01/19 15:43:57 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 David Roberts
2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#include "HTTPXHTMLHeader.h"
cgicc::HTTPXHTMLHeader::HTTPXHTMLHeader() : HTTPContentHeader("application/xhtml+xml") {}
cgicc::HTTPXHTMLHeader::~HTTPXHTMLHeader() {}

View File

@ -0,0 +1,66 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: HTTPXHTMLHeader.h,v 1.2 2014/04/23 20:55:09 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 David Roberts
2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef HTTPXHTMLHEADER_H
#define HTTPXHTMLHEADER_H
#include "HTTPContentHeader.h"
/*! \file HTTPXHTMLHeader.h
* \brief Class that abstracts a XHTML Content Header
*
* This class add the XHTML feature
*/
namespace cgicc {
/*! \class HTTPXHTMLHeader HTTPXHTMLHeader.h cgicc/HTTPXHTMLHeader.h
* \brief Class that abstracts a XHTML Content Header
*
* This class add the XHTML feature
*/
class CGICC_API HTTPXHTMLHeader : public HTTPContentHeader {
public:
// ============================================================
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Constructor
*
* Create a new HTTPXHTMLHeader object
*/
HTTPXHTMLHeader();
/*!
* \brief Destructor
*
* Delete this HTTPXHTMLHeader object
*/
virtual ~HTTPXHTMLHeader();
//@}
};
}// namespace cgicc
#endif

View File

@ -0,0 +1,39 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: MStreamable.cpp,v 1.10 2014/04/23 20:55:09 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include "MStreamable.h"
// ============================================================
// Class MStreamable
// ============================================================
std::ostream&
cgicc::operator<<(std::ostream& out,
const MStreamable& obj)
{
obj.render(out);
return out;
}

View File

@ -0,0 +1,100 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: MStreamable.h,v 1.14 2014/12/07 14:33:02 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef _MSTREAMABLE_H_
#define _MSTREAMABLE_H_ 1
#ifdef __GNUG__
# pragma interface
#endif
/*! \file MStreamable.h
* \brief Abstract base class for all streamable objects.
*
* A streamable object is an object that can be written to an \c
* ostream using the \c << operator.
*/
#include <iostream>
#include "CgiDefs.h"
namespace cgicc {
class MStreamable;
/*!
* Prototype for overloading streaming operator
* \param out The ostream to which to write
* \param obj The MStreamable object to write
* \return A reference to \c out
*/
CGICC_API std::ostream&
operator<<(std::ostream& out, const MStreamable& obj);
// ============================================================
// Class MStreamable
// ============================================================
/*! \class MStreamable MStreamable.h cgicc/MStreamable.h
* \brief Mix-in streamable interface.
*
* Abstract mix-in class which makes classes streamable via
* the \c << operator.
* Written in the spirit of a Java interface.
*/
class CGICC_API MStreamable
{
friend CGICC_API std::ostream&
operator<<(std::ostream& out, const MStreamable& obj);
public:
/*!
* \brief Empty constructor
*
*/
inline MStreamable()
{}
/*!
* \brief Empty destructor
*
*/
inline virtual ~MStreamable()
{}
/*!
* \brief Write this object to a stream.
*
* Subclasses must implement this function.
* \param out The ostream to which to write.
*/
virtual void
render(std::ostream& out) const = 0;
};
} // namespace cgicc
#endif /* ! _MSTREAMABLE_H_ */

View File

@ -0,0 +1,30 @@
## $Id: Makefile.am,v 1.29 2014/04/23 20:55:10 sebdiaz Exp $
CLEANFILES = *~
ACLOCAL_AMFLAGS=
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir)
lib_LTLIBRARIES = libcgicc.la
libcgicc_la_SOURCES = CgiEnvironment.cpp CgiInput.cpp CgiUtils.cpp \
Cgicc.cpp FormEntry.cpp FormFile.cpp HTMLAttribute.cpp \
HTMLAttributeList.cpp HTMLDoctype.cpp HTMLElement.cpp \
HTMLElementList.cpp HTTPContentHeader.cpp HTTPCookie.cpp \
HTTPHTMLHeader.cpp HTTPHeader.cpp HTTPPlainHeader.cpp \
HTTPRedirectHeader.cpp HTTPResponseHeader.cpp HTTPStatusHeader.cpp \
MStreamable.cpp \
HTTPXHTMLHeader.cpp XHTMLDoctype.cpp XMLPI.cpp
libcgicc_la_LDFLAGS = -lstdc++ -version-info 5:10:2
pkginclude_HEADERS = CgiDefs.h CgiEnvironment.h CgiInput.h CgiUtils.h \
Cgicc.h FormEntry.h FormFile.h HTMLAtomicElement.h HTMLAttribute.h \
HTMLAttributeList.h HTMLBooleanElement.h HTMLClasses.h HTMLDoctype.h \
HTMLElement.h HTMLElementList.h HTTPContentHeader.h HTTPCookie.h \
HTTPHTMLHeader.h HTTPHeader.h HTTPPlainHeader.h HTTPRedirectHeader.h \
HTTPResponseHeader.h HTTPStatusHeader.h MStreamable.h \
HTTPXHTMLHeader.h XHTMLDoctype.h XMLDeclaration.h XMLPI.h
libcgicc_la_CPPFLAGS = -x c++
libcgicc_la_LIBADD =

View File

@ -0,0 +1,915 @@
# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = cgicc
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(pkginclude_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = CgiDefs.h
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgincludedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libcgicc_la_DEPENDENCIES =
am_libcgicc_la_OBJECTS = libcgicc_la-CgiEnvironment.lo \
libcgicc_la-CgiInput.lo libcgicc_la-CgiUtils.lo \
libcgicc_la-Cgicc.lo libcgicc_la-FormEntry.lo \
libcgicc_la-FormFile.lo libcgicc_la-HTMLAttribute.lo \
libcgicc_la-HTMLAttributeList.lo libcgicc_la-HTMLDoctype.lo \
libcgicc_la-HTMLElement.lo libcgicc_la-HTMLElementList.lo \
libcgicc_la-HTTPContentHeader.lo libcgicc_la-HTTPCookie.lo \
libcgicc_la-HTTPHTMLHeader.lo libcgicc_la-HTTPHeader.lo \
libcgicc_la-HTTPPlainHeader.lo \
libcgicc_la-HTTPRedirectHeader.lo \
libcgicc_la-HTTPResponseHeader.lo \
libcgicc_la-HTTPStatusHeader.lo libcgicc_la-MStreamable.lo \
libcgicc_la-HTTPXHTMLHeader.lo libcgicc_la-XHTMLDoctype.lo \
libcgicc_la-XMLPI.lo
libcgicc_la_OBJECTS = $(am_libcgicc_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
libcgicc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(libcgicc_la_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/support/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_@AM_V@)
am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
am__v_CXX_0 = @echo " CXX " $@;
am__v_CXX_1 =
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
am__v_CXXLD_0 = @echo " CXXLD " $@;
am__v_CXXLD_1 =
SOURCES = $(libcgicc_la_SOURCES)
DIST_SOURCES = $(libcgicc_la_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(pkginclude_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
$(LISP)config.h.in
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/CgiDefs.h.in $(srcdir)/Makefile.in \
$(srcdir)/config.h.in $(top_srcdir)/support/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEMO_LIBS = @DEMO_LIBS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FCGI_LIBS = @FCGI_LIBS@
FGREP = @FGREP@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIB_NET = @LIB_NET@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
CLEANFILES = *~
ACLOCAL_AMFLAGS =
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir)
lib_LTLIBRARIES = libcgicc.la
libcgicc_la_SOURCES = CgiEnvironment.cpp CgiInput.cpp CgiUtils.cpp \
Cgicc.cpp FormEntry.cpp FormFile.cpp HTMLAttribute.cpp \
HTMLAttributeList.cpp HTMLDoctype.cpp HTMLElement.cpp \
HTMLElementList.cpp HTTPContentHeader.cpp HTTPCookie.cpp \
HTTPHTMLHeader.cpp HTTPHeader.cpp HTTPPlainHeader.cpp \
HTTPRedirectHeader.cpp HTTPResponseHeader.cpp HTTPStatusHeader.cpp \
MStreamable.cpp \
HTTPXHTMLHeader.cpp XHTMLDoctype.cpp XMLPI.cpp
libcgicc_la_LDFLAGS = -lstdc++ -version-info 5:10:2
pkginclude_HEADERS = CgiDefs.h CgiEnvironment.h CgiInput.h CgiUtils.h \
Cgicc.h FormEntry.h FormFile.h HTMLAtomicElement.h HTMLAttribute.h \
HTMLAttributeList.h HTMLBooleanElement.h HTMLClasses.h HTMLDoctype.h \
HTMLElement.h HTMLElementList.h HTTPContentHeader.h HTTPCookie.h \
HTTPHTMLHeader.h HTTPHeader.h HTTPPlainHeader.h HTTPRedirectHeader.h \
HTTPResponseHeader.h HTTPStatusHeader.h MStreamable.h \
HTTPXHTMLHeader.h XHTMLDoctype.h XMLDeclaration.h XMLPI.h
libcgicc_la_CPPFLAGS = -x c++
libcgicc_la_LIBADD =
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .cpp .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu cgicc/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu cgicc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
config.h: stamp-h1
@test -f $@ || rm -f stamp-h1
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status cgicc/config.h
$(srcdir)/config.h.in: $(am__configure_deps)
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
rm -f stamp-h1
touch $@
distclean-hdr:
-rm -f config.h stamp-h1
CgiDefs.h: $(top_builddir)/config.status $(srcdir)/CgiDefs.h.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
}
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
done
clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libcgicc.la: $(libcgicc_la_OBJECTS) $(libcgicc_la_DEPENDENCIES) $(EXTRA_libcgicc_la_DEPENDENCIES)
$(AM_V_CXXLD)$(libcgicc_la_LINK) -rpath $(libdir) $(libcgicc_la_OBJECTS) $(libcgicc_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-CgiEnvironment.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-CgiInput.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-CgiUtils.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-Cgicc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-FormEntry.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-FormFile.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTMLAttribute.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTMLAttributeList.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTMLDoctype.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTMLElement.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTMLElementList.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPContentHeader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPCookie.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPHTMLHeader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPHeader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPPlainHeader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPRedirectHeader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPResponseHeader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPStatusHeader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-HTTPXHTMLHeader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-MStreamable.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-XHTMLDoctype.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcgicc_la-XMLPI.Plo@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cpp.lo:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
libcgicc_la-CgiEnvironment.lo: CgiEnvironment.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-CgiEnvironment.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-CgiEnvironment.Tpo -c -o libcgicc_la-CgiEnvironment.lo `test -f 'CgiEnvironment.cpp' || echo '$(srcdir)/'`CgiEnvironment.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-CgiEnvironment.Tpo $(DEPDIR)/libcgicc_la-CgiEnvironment.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CgiEnvironment.cpp' object='libcgicc_la-CgiEnvironment.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-CgiEnvironment.lo `test -f 'CgiEnvironment.cpp' || echo '$(srcdir)/'`CgiEnvironment.cpp
libcgicc_la-CgiInput.lo: CgiInput.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-CgiInput.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-CgiInput.Tpo -c -o libcgicc_la-CgiInput.lo `test -f 'CgiInput.cpp' || echo '$(srcdir)/'`CgiInput.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-CgiInput.Tpo $(DEPDIR)/libcgicc_la-CgiInput.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CgiInput.cpp' object='libcgicc_la-CgiInput.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-CgiInput.lo `test -f 'CgiInput.cpp' || echo '$(srcdir)/'`CgiInput.cpp
libcgicc_la-CgiUtils.lo: CgiUtils.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-CgiUtils.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-CgiUtils.Tpo -c -o libcgicc_la-CgiUtils.lo `test -f 'CgiUtils.cpp' || echo '$(srcdir)/'`CgiUtils.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-CgiUtils.Tpo $(DEPDIR)/libcgicc_la-CgiUtils.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CgiUtils.cpp' object='libcgicc_la-CgiUtils.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-CgiUtils.lo `test -f 'CgiUtils.cpp' || echo '$(srcdir)/'`CgiUtils.cpp
libcgicc_la-Cgicc.lo: Cgicc.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-Cgicc.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-Cgicc.Tpo -c -o libcgicc_la-Cgicc.lo `test -f 'Cgicc.cpp' || echo '$(srcdir)/'`Cgicc.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-Cgicc.Tpo $(DEPDIR)/libcgicc_la-Cgicc.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Cgicc.cpp' object='libcgicc_la-Cgicc.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-Cgicc.lo `test -f 'Cgicc.cpp' || echo '$(srcdir)/'`Cgicc.cpp
libcgicc_la-FormEntry.lo: FormEntry.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-FormEntry.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-FormEntry.Tpo -c -o libcgicc_la-FormEntry.lo `test -f 'FormEntry.cpp' || echo '$(srcdir)/'`FormEntry.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-FormEntry.Tpo $(DEPDIR)/libcgicc_la-FormEntry.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='FormEntry.cpp' object='libcgicc_la-FormEntry.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-FormEntry.lo `test -f 'FormEntry.cpp' || echo '$(srcdir)/'`FormEntry.cpp
libcgicc_la-FormFile.lo: FormFile.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-FormFile.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-FormFile.Tpo -c -o libcgicc_la-FormFile.lo `test -f 'FormFile.cpp' || echo '$(srcdir)/'`FormFile.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-FormFile.Tpo $(DEPDIR)/libcgicc_la-FormFile.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='FormFile.cpp' object='libcgicc_la-FormFile.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-FormFile.lo `test -f 'FormFile.cpp' || echo '$(srcdir)/'`FormFile.cpp
libcgicc_la-HTMLAttribute.lo: HTMLAttribute.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTMLAttribute.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTMLAttribute.Tpo -c -o libcgicc_la-HTMLAttribute.lo `test -f 'HTMLAttribute.cpp' || echo '$(srcdir)/'`HTMLAttribute.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTMLAttribute.Tpo $(DEPDIR)/libcgicc_la-HTMLAttribute.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTMLAttribute.cpp' object='libcgicc_la-HTMLAttribute.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTMLAttribute.lo `test -f 'HTMLAttribute.cpp' || echo '$(srcdir)/'`HTMLAttribute.cpp
libcgicc_la-HTMLAttributeList.lo: HTMLAttributeList.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTMLAttributeList.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTMLAttributeList.Tpo -c -o libcgicc_la-HTMLAttributeList.lo `test -f 'HTMLAttributeList.cpp' || echo '$(srcdir)/'`HTMLAttributeList.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTMLAttributeList.Tpo $(DEPDIR)/libcgicc_la-HTMLAttributeList.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTMLAttributeList.cpp' object='libcgicc_la-HTMLAttributeList.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTMLAttributeList.lo `test -f 'HTMLAttributeList.cpp' || echo '$(srcdir)/'`HTMLAttributeList.cpp
libcgicc_la-HTMLDoctype.lo: HTMLDoctype.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTMLDoctype.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTMLDoctype.Tpo -c -o libcgicc_la-HTMLDoctype.lo `test -f 'HTMLDoctype.cpp' || echo '$(srcdir)/'`HTMLDoctype.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTMLDoctype.Tpo $(DEPDIR)/libcgicc_la-HTMLDoctype.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTMLDoctype.cpp' object='libcgicc_la-HTMLDoctype.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTMLDoctype.lo `test -f 'HTMLDoctype.cpp' || echo '$(srcdir)/'`HTMLDoctype.cpp
libcgicc_la-HTMLElement.lo: HTMLElement.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTMLElement.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTMLElement.Tpo -c -o libcgicc_la-HTMLElement.lo `test -f 'HTMLElement.cpp' || echo '$(srcdir)/'`HTMLElement.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTMLElement.Tpo $(DEPDIR)/libcgicc_la-HTMLElement.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTMLElement.cpp' object='libcgicc_la-HTMLElement.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTMLElement.lo `test -f 'HTMLElement.cpp' || echo '$(srcdir)/'`HTMLElement.cpp
libcgicc_la-HTMLElementList.lo: HTMLElementList.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTMLElementList.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTMLElementList.Tpo -c -o libcgicc_la-HTMLElementList.lo `test -f 'HTMLElementList.cpp' || echo '$(srcdir)/'`HTMLElementList.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTMLElementList.Tpo $(DEPDIR)/libcgicc_la-HTMLElementList.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTMLElementList.cpp' object='libcgicc_la-HTMLElementList.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTMLElementList.lo `test -f 'HTMLElementList.cpp' || echo '$(srcdir)/'`HTMLElementList.cpp
libcgicc_la-HTTPContentHeader.lo: HTTPContentHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPContentHeader.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPContentHeader.Tpo -c -o libcgicc_la-HTTPContentHeader.lo `test -f 'HTTPContentHeader.cpp' || echo '$(srcdir)/'`HTTPContentHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPContentHeader.Tpo $(DEPDIR)/libcgicc_la-HTTPContentHeader.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPContentHeader.cpp' object='libcgicc_la-HTTPContentHeader.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPContentHeader.lo `test -f 'HTTPContentHeader.cpp' || echo '$(srcdir)/'`HTTPContentHeader.cpp
libcgicc_la-HTTPCookie.lo: HTTPCookie.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPCookie.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPCookie.Tpo -c -o libcgicc_la-HTTPCookie.lo `test -f 'HTTPCookie.cpp' || echo '$(srcdir)/'`HTTPCookie.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPCookie.Tpo $(DEPDIR)/libcgicc_la-HTTPCookie.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPCookie.cpp' object='libcgicc_la-HTTPCookie.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPCookie.lo `test -f 'HTTPCookie.cpp' || echo '$(srcdir)/'`HTTPCookie.cpp
libcgicc_la-HTTPHTMLHeader.lo: HTTPHTMLHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPHTMLHeader.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPHTMLHeader.Tpo -c -o libcgicc_la-HTTPHTMLHeader.lo `test -f 'HTTPHTMLHeader.cpp' || echo '$(srcdir)/'`HTTPHTMLHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPHTMLHeader.Tpo $(DEPDIR)/libcgicc_la-HTTPHTMLHeader.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPHTMLHeader.cpp' object='libcgicc_la-HTTPHTMLHeader.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPHTMLHeader.lo `test -f 'HTTPHTMLHeader.cpp' || echo '$(srcdir)/'`HTTPHTMLHeader.cpp
libcgicc_la-HTTPHeader.lo: HTTPHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPHeader.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPHeader.Tpo -c -o libcgicc_la-HTTPHeader.lo `test -f 'HTTPHeader.cpp' || echo '$(srcdir)/'`HTTPHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPHeader.Tpo $(DEPDIR)/libcgicc_la-HTTPHeader.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPHeader.cpp' object='libcgicc_la-HTTPHeader.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPHeader.lo `test -f 'HTTPHeader.cpp' || echo '$(srcdir)/'`HTTPHeader.cpp
libcgicc_la-HTTPPlainHeader.lo: HTTPPlainHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPPlainHeader.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPPlainHeader.Tpo -c -o libcgicc_la-HTTPPlainHeader.lo `test -f 'HTTPPlainHeader.cpp' || echo '$(srcdir)/'`HTTPPlainHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPPlainHeader.Tpo $(DEPDIR)/libcgicc_la-HTTPPlainHeader.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPPlainHeader.cpp' object='libcgicc_la-HTTPPlainHeader.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPPlainHeader.lo `test -f 'HTTPPlainHeader.cpp' || echo '$(srcdir)/'`HTTPPlainHeader.cpp
libcgicc_la-HTTPRedirectHeader.lo: HTTPRedirectHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPRedirectHeader.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPRedirectHeader.Tpo -c -o libcgicc_la-HTTPRedirectHeader.lo `test -f 'HTTPRedirectHeader.cpp' || echo '$(srcdir)/'`HTTPRedirectHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPRedirectHeader.Tpo $(DEPDIR)/libcgicc_la-HTTPRedirectHeader.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPRedirectHeader.cpp' object='libcgicc_la-HTTPRedirectHeader.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPRedirectHeader.lo `test -f 'HTTPRedirectHeader.cpp' || echo '$(srcdir)/'`HTTPRedirectHeader.cpp
libcgicc_la-HTTPResponseHeader.lo: HTTPResponseHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPResponseHeader.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPResponseHeader.Tpo -c -o libcgicc_la-HTTPResponseHeader.lo `test -f 'HTTPResponseHeader.cpp' || echo '$(srcdir)/'`HTTPResponseHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPResponseHeader.Tpo $(DEPDIR)/libcgicc_la-HTTPResponseHeader.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPResponseHeader.cpp' object='libcgicc_la-HTTPResponseHeader.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPResponseHeader.lo `test -f 'HTTPResponseHeader.cpp' || echo '$(srcdir)/'`HTTPResponseHeader.cpp
libcgicc_la-HTTPStatusHeader.lo: HTTPStatusHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPStatusHeader.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPStatusHeader.Tpo -c -o libcgicc_la-HTTPStatusHeader.lo `test -f 'HTTPStatusHeader.cpp' || echo '$(srcdir)/'`HTTPStatusHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPStatusHeader.Tpo $(DEPDIR)/libcgicc_la-HTTPStatusHeader.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPStatusHeader.cpp' object='libcgicc_la-HTTPStatusHeader.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPStatusHeader.lo `test -f 'HTTPStatusHeader.cpp' || echo '$(srcdir)/'`HTTPStatusHeader.cpp
libcgicc_la-MStreamable.lo: MStreamable.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-MStreamable.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-MStreamable.Tpo -c -o libcgicc_la-MStreamable.lo `test -f 'MStreamable.cpp' || echo '$(srcdir)/'`MStreamable.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-MStreamable.Tpo $(DEPDIR)/libcgicc_la-MStreamable.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='MStreamable.cpp' object='libcgicc_la-MStreamable.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-MStreamable.lo `test -f 'MStreamable.cpp' || echo '$(srcdir)/'`MStreamable.cpp
libcgicc_la-HTTPXHTMLHeader.lo: HTTPXHTMLHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-HTTPXHTMLHeader.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-HTTPXHTMLHeader.Tpo -c -o libcgicc_la-HTTPXHTMLHeader.lo `test -f 'HTTPXHTMLHeader.cpp' || echo '$(srcdir)/'`HTTPXHTMLHeader.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-HTTPXHTMLHeader.Tpo $(DEPDIR)/libcgicc_la-HTTPXHTMLHeader.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HTTPXHTMLHeader.cpp' object='libcgicc_la-HTTPXHTMLHeader.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-HTTPXHTMLHeader.lo `test -f 'HTTPXHTMLHeader.cpp' || echo '$(srcdir)/'`HTTPXHTMLHeader.cpp
libcgicc_la-XHTMLDoctype.lo: XHTMLDoctype.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-XHTMLDoctype.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-XHTMLDoctype.Tpo -c -o libcgicc_la-XHTMLDoctype.lo `test -f 'XHTMLDoctype.cpp' || echo '$(srcdir)/'`XHTMLDoctype.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-XHTMLDoctype.Tpo $(DEPDIR)/libcgicc_la-XHTMLDoctype.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='XHTMLDoctype.cpp' object='libcgicc_la-XHTMLDoctype.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-XHTMLDoctype.lo `test -f 'XHTMLDoctype.cpp' || echo '$(srcdir)/'`XHTMLDoctype.cpp
libcgicc_la-XMLPI.lo: XMLPI.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcgicc_la-XMLPI.lo -MD -MP -MF $(DEPDIR)/libcgicc_la-XMLPI.Tpo -c -o libcgicc_la-XMLPI.lo `test -f 'XMLPI.cpp' || echo '$(srcdir)/'`XMLPI.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcgicc_la-XMLPI.Tpo $(DEPDIR)/libcgicc_la-XMLPI.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='XMLPI.cpp' object='libcgicc_la-XMLPI.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcgicc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcgicc_la-XMLPI.lo `test -f 'XMLPI.cpp' || echo '$(srcdir)/'`XMLPI.cpp
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-pkgincludeHEADERS: $(pkginclude_HEADERS)
@$(NORMAL_INSTALL)
@list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \
done
uninstall-pkgincludeHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h
installdirs:
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgincludedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-pkgincludeHEADERS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-libLTLIBRARIES
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-libLTLIBRARIES uninstall-pkgincludeHEADERS
.MAKE: all install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
ctags-am distclean distclean-compile distclean-generic \
distclean-hdr distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-libLTLIBRARIES \
install-man install-pdf install-pdf-am \
install-pkgincludeHEADERS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-libLTLIBRARIES uninstall-pkgincludeHEADERS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,53 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: XHTMLDoctype.cpp,v 1.2 2014/12/07 14:33:03 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 David Roberts
2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#include "XHTMLDoctype.h"
cgicc::XHTMLDoctype::XHTMLDoctype(EDocumentType type) : fType(type) {}
cgicc::XHTMLDoctype::~XHTMLDoctype() {}
void cgicc::XHTMLDoctype::render(std::ostream &out) const {
out << "<!DOCTYPE html";
bool bHTML5 = false;
switch(fType) {
case eStrict: out << " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict"; break;
case eTransitional: out << " PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional"; break;
case eFrames: out << " PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset"; break;
case eHTML5: bHTML5 = true; break;
}
if(bHTML5 == false)
out << "//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-";
switch(fType) {
case eStrict: out << "strict"; break;
case eTransitional: out << "transitional"; break;
case eFrames: out << "frameset"; break;
case eHTML5: break;
}
out << ".dtd\">";
}

View File

@ -0,0 +1,83 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: XHTMLDoctype.h,v 1.4 2017/06/22 20:26:35 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 David Roberts
2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef XXHTMLDoctype_H
#define XXHTMLDoctype_H
/*! \file XHTMLDoctype.h
* \brief Class that abstracts a XHTML Doc Type
*
* This class add the XHTML Doc feature
*/
#include <string>
#include "MStreamable.h"
namespace cgicc {
/*! \class XHTMLDoctype XHTMLDoctype.h cgicc/XHTMLDoctype.h
* \brief Class that abstracts a XHTML Doc Type
*
* This class add the XHTML Doc Type feature
*/
class CGICC_API XHTMLDoctype : public MStreamable {
public:
enum EDocumentType {
eStrict,
eTransitional,
eFrames,
eHTML5 // 11.30.14 t.o.
};
// ============================================================
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Constructor
*
* Create a new XHTMLDoctype.h object
* \param input The Document Type
*/
XHTMLDoctype(EDocumentType type = eStrict);
/*!
* \brief Destructor
*
* Delete this XHTMLDoctype.h object
*/
virtual ~XHTMLDoctype();
//@}
virtual void render(std::ostream& out) const;
private:
EDocumentType fType;
};
}// namespace cgicc
/// XHMTL namespace attribute for html tag - usage: html().xmlnsXHTML()
#define xmlnsXHTML() set("xmlns", "http://www.w3.org/1999/xhtml")
#endif

View File

@ -0,0 +1,67 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: XMLDeclaration.h,v 1.2 2014/12/07 14:33:03 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 David Roberts
2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef XMLDECLARATION_H
#define XMLDECLARATION_H
/*! \file XMLDeclaration.h
* \brief Class that abstracts a XML Declaration
*
* This class add the XML Declaration feature
*/
#include "XMLPI.h"
#include <string>
namespace cgicc{
/*! \class XMLDeclaration XMLDeclaration.h cgicc/XMLDeclaration.h
* \brief Class that abstracts a XMLDeclaration
*
* This class add the XMLDeclaration feature
*/
class XMLDeclaration : public XMLPI {
public:
// ============================================================
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Constructor
*
* Create a new XMLDeclaration.h object
* \param input The Xml version (generally 1.0 or 1.1)
*/
XMLDeclaration(std::string version = "1.0") : XMLPI("xml") { set("version", version); }
/*!
* \brief Destructor
*
* Delete this XMLDeclaration object
*/
virtual ~XMLDeclaration(){};
//@}
};
}// namespace cgicc
#endif

View File

@ -0,0 +1,64 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: XMLPI.cpp,v 1.1 2008/01/19 15:43:57 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 David Roberts
2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#include "XMLPI.h"
cgicc::XMLPI::XMLPI(std::string name) : MStreamable(), fAttributes(0), fName(name) {}
cgicc::XMLPI::~XMLPI() {
delete fAttributes;
}
cgicc::XMLPI& cgicc::XMLPI::operator= (const XMLPI& element) {
delete fAttributes;
fAttributes = element.fAttributes;
if(fAttributes != 0) fAttributes = new HTMLAttributeList(*fAttributes);
return *this;
}
void cgicc::XMLPI::setAttributes(const HTMLAttributeList& attributes) {
delete fAttributes;
fAttributes = new HTMLAttributeList(attributes);
}
cgicc::XMLPI& cgicc::XMLPI::set(const std::string& name) {
if(fAttributes == 0) fAttributes = new HTMLAttributeList();
fAttributes->set(name);
return *this;
}
cgicc::XMLPI& cgicc::XMLPI::set(const std::string& name, const std::string& value) {
if(fAttributes == 0) fAttributes = new HTMLAttributeList();
fAttributes->set(name, value);
return *this;
}
void cgicc::XMLPI::render(std::ostream& out) const {
out << "<?" << fName;
if(getAttributes() != 0) {
out << ' ';
fAttributes->render(out);
}
out << "?>";
}

View File

@ -0,0 +1,82 @@
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: XMLPI.h,v 1.2 2014/04/23 20:55:10 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 David Roberts
2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
#ifndef XMLPI_H
#define XMLPI_H
/*! \file XMLPI.h
* \brief Class that abstracts a XMLPI
*
* This class add the XML Declaration feature
*/
#include <string>
#include "CgiDefs.h"
#include "MStreamable.h"
#include "HTMLAttributeList.h"
namespace cgicc {
/*! \class XMLPI XMLPI.h cgicc/XMLPI.h
* \brief Class that abstracts a XMLPI
*
* This class add the XMLPI feature
*/
class XMLPI : public MStreamable {
public:
// ============================================================
/*! \name Constructor and Destructor */
//@{
/*!
* \brief Constructor
*
* Create a new XMLPI.h object
* \param input The name of the XMLPI
*/
XMLPI(std::string name);
/*!
* \brief Destructor
*
* Delete this XMLPI object
*/
virtual ~XMLPI();
//@}
XMLPI& operator= (const XMLPI& element);
inline std::string getName() const { return fName; }
inline const HTMLAttributeList* getAttributes() const { return fAttributes; }
void setAttributes(const HTMLAttributeList& attributes);
XMLPI& set(const std::string& name);
XMLPI& set(const std::string& name, const std::string& value);
virtual void render(std::ostream& out) const;
private:
HTMLAttributeList* fAttributes;
std::string fName;
};
}// namespace cgicc
#endif

View File

@ -0,0 +1,118 @@
/* cgicc/config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `gethostbyaddr' function. */
#undef HAVE_GETHOSTBYADDR
/* Define to 1 if you have the `gethostbyname' function. */
#undef HAVE_GETHOSTBYNAME
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the `inet_ntoa' function. */
#undef HAVE_INET_NTOA
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* define if the compiler implements namespaces */
#undef HAVE_NAMESPACES
/* Define to 1 if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H
/* Define to 1 if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* define if the compiler supports Standard Template Library */
#undef HAVE_STL
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the `uname' function. */
#undef HAVE_UNAME
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* The host system cgicc was configured for */
#undef HOST
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t

View File

@ -0,0 +1,15 @@
#ifndef HV_BUFFER_HPP_
#define HV_BUFFER_HPP_
#include <memory>
#include "hbuf.h"
namespace hv {
typedef HBuf Buffer;
typedef std::shared_ptr<Buffer> BufferPtr;
}
#endif // HV_BUFFER_HPP_

View File

@ -0,0 +1,336 @@
#ifndef HV_CHANNEL_HPP_
#define HV_CHANNEL_HPP_
#include <string>
#include <functional>
#include <memory>
#include "hloop.h"
#include "hsocket.h"
#include "Buffer.h"
namespace hv {
class Channel {
public:
Channel(hio_t* io = NULL) {
io_ = io;
fd_ = -1;
id_ = 0;
ctx_ = NULL;
status = CLOSED;
if (io) {
fd_ = hio_fd(io);
id_ = hio_id(io);
ctx_ = hio_context(io);
hio_set_context(io, this);
if (hio_is_opened(io)) {
status = OPENED;
}
if (hio_getcb_read(io) == NULL) {
hio_setcb_read(io_, on_read);
}
if (hio_getcb_write(io) == NULL) {
hio_setcb_write(io_, on_write);
}
if (hio_getcb_close(io) == NULL) {
hio_setcb_close(io_, on_close);
}
}
}
virtual ~Channel() {
close();
}
hio_t* io() { return io_; }
int fd() { return fd_; }
uint32_t id() { return id_; }
int error() { return hio_error(io_); }
// context
void* context() {
return ctx_;
}
void setContext(void* ctx) {
ctx_ = ctx;
}
template<class T>
T* newContext() {
ctx_ = new T;
return (T*)ctx_;
}
template<class T>
T* getContext() {
return (T*)ctx_;
}
template<class T>
void deleteContext() {
if (ctx_) {
delete (T*)ctx_;
ctx_ = NULL;
}
}
bool isOpened() {
if (io_ == NULL || status >= DISCONNECTED) return false;
return id_ == hio_id(io_) && hio_is_opened(io_);
}
bool isClosed() {
return !isOpened();
}
int startRead() {
if (!isOpened()) return -1;
return hio_read_start(io_);
}
int stopRead() {
if (!isOpened()) return -1;
return hio_read_stop(io_);
}
int readOnce() {
if (!isOpened()) return -1;
return hio_read_once(io_);
}
int readString() {
if (!isOpened()) return -1;
return hio_readstring(io_);
}
int readLine() {
if (!isOpened()) return -1;
return hio_readline(io_);
}
int readBytes(int len) {
if (!isOpened() || len <= 0) return -1;
return hio_readbytes(io_, len);
}
// write thread-safe
int write(const void* data, int size) {
if (!isOpened()) return -1;
return hio_write(io_, data, size);
}
int write(Buffer* buf) {
return write(buf->data(), buf->size());
}
int write(const std::string& str) {
return write(str.data(), str.size());
}
// iobuf setting
void setMaxReadBufsize(uint32_t size) {
if (io_ == NULL) return;
return hio_set_max_read_bufsize(io_, size);
}
void setMaxWriteBufsize(uint32_t size) {
if (io_ == NULL) return;
return hio_set_max_write_bufsize(io_, size);
}
size_t writeBufsize() {
if (io_ == NULL) return 0;
return hio_write_bufsize(io_);
}
bool isWriteComplete() {
return writeBufsize() == 0;
}
// close thread-safe
int close(bool async = false) {
if (!isOpened()) return -1;
if (async) {
return hio_close_async(io_);
}
return hio_close(io_);
}
public:
hio_t* io_;
int fd_;
uint32_t id_;
void* ctx_;
enum Status {
OPENED,
CONNECTING,
CONNECTED,
DISCONNECTED,
CLOSED,
} status;
std::function<void(Buffer*)> onread;
// NOTE: Use Channel::isWriteComplete in onwrite callback to determine whether all data has been written.
std::function<void(Buffer*)> onwrite;
std::function<void()> onclose;
private:
static void on_read(hio_t* io, void* data, int readbytes) {
Channel* channel = (Channel*)hio_context(io);
if (channel && channel->onread) {
Buffer buf(data, readbytes);
channel->onread(&buf);
}
}
static void on_write(hio_t* io, const void* data, int writebytes) {
Channel* channel = (Channel*)hio_context(io);
if (channel && channel->onwrite) {
Buffer buf((void*)data, writebytes);
channel->onwrite(&buf);
}
}
static void on_close(hio_t* io) {
Channel* channel = (Channel*)hio_context(io);
if (channel) {
channel->status = CLOSED;
if (channel->onclose) {
channel->onclose();
}
}
}
};
class SocketChannel : public Channel {
public:
std::function<void()> onconnect; // only for TcpClient
std::function<void()> heartbeat;
SocketChannel(hio_t* io) : Channel(io) {
}
virtual ~SocketChannel() {}
// SSL/TLS
int enableSSL() {
if (io_ == NULL) return -1;
return hio_enable_ssl(io_);
}
bool isSSL() {
if (io_ == NULL) return false;
return hio_is_ssl(io_);
}
int setSSL(hssl_t ssl) {
if (io_ == NULL) return -1;
return hio_set_ssl(io_, ssl);
}
int setSslCtx(hssl_ctx_t ssl_ctx) {
if (io_ == NULL) return -1;
return hio_set_ssl_ctx(io_, ssl_ctx);
}
int newSslCtx(hssl_ctx_opt_t* opt) {
if (io_ == NULL) return -1;
return hio_new_ssl_ctx(io_, opt);
}
// for hssl_set_sni_hostname
int setHostname(const std::string& hostname) {
if (io_ == NULL) return -1;
return hio_set_hostname(io_, hostname.c_str());
}
// timeout
void setConnectTimeout(int timeout_ms) {
if (io_ == NULL) return;
hio_set_connect_timeout(io_, timeout_ms);
}
void setCloseTimeout(int timeout_ms) {
if (io_ == NULL) return;
hio_set_close_timeout(io_, timeout_ms);
}
void setReadTimeout(int timeout_ms) {
if (io_ == NULL) return;
hio_set_read_timeout(io_, timeout_ms);
}
void setWriteTimeout(int timeout_ms) {
if (io_ == NULL) return;
hio_set_write_timeout(io_, timeout_ms);
}
void setKeepaliveTimeout(int timeout_ms) {
if (io_ == NULL) return;
hio_set_keepalive_timeout(io_, timeout_ms);
}
// heartbeat
void setHeartbeat(int interval_ms, std::function<void()> fn) {
if (io_ == NULL) return;
heartbeat = std::move(fn);
hio_set_heartbeat(io_, interval_ms, send_heartbeat);
}
// unpack
void setUnpack(unpack_setting_t* setting) {
if (io_ == NULL) return;
hio_set_unpack(io_, setting);
}
int startConnect(int port, const char* host = "127.0.0.1") {
sockaddr_u peeraddr;
memset(&peeraddr, 0, sizeof(peeraddr));
int ret = sockaddr_set_ipport(&peeraddr, host, port);
if (ret != 0) {
// hloge("unknown host %s", host);
return ret;
}
return startConnect(&peeraddr.sa);
}
int startConnect(struct sockaddr* peeraddr) {
if (io_ == NULL) return -1;
hio_set_peeraddr(io_, peeraddr, SOCKADDR_LEN(peeraddr));
return startConnect();
}
int startConnect() {
if (io_ == NULL) return -1;
status = CONNECTING;
hio_setcb_connect(io_, on_connect);
return hio_connect(io_);
}
bool isConnected() {
return status == CONNECTED && isOpened();
}
std::string localaddr() {
if (io_ == NULL) return "";
struct sockaddr* addr = hio_localaddr(io_);
char buf[SOCKADDR_STRLEN] = {0};
return SOCKADDR_STR(addr, buf);
}
std::string peeraddr() {
if (io_ == NULL) return "";
struct sockaddr* addr = hio_peeraddr(io_);
char buf[SOCKADDR_STRLEN] = {0};
return SOCKADDR_STR(addr, buf);
}
private:
static void on_connect(hio_t* io) {
SocketChannel* channel = (SocketChannel*)hio_context(io);
if (channel) {
channel->status = CONNECTED;
if (channel->onconnect) {
channel->onconnect();
}
}
}
static void send_heartbeat(hio_t* io) {
SocketChannel* channel = (SocketChannel*)hio_context(io);
if (channel && channel->heartbeat) {
channel->heartbeat();
}
}
};
typedef std::shared_ptr<Channel> ChannelPtr;
typedef std::shared_ptr<SocketChannel> SocketChannelPtr;
}
#endif // HV_CHANNEL_HPP_

View File

@ -0,0 +1,47 @@
#ifndef HV_EVENT_HPP_
#define HV_EVENT_HPP_
#include <functional>
#include <memory>
#include "hloop.h"
namespace hv {
struct Event;
struct Timer;
typedef uint64_t TimerID;
#define INVALID_TIMER_ID ((TimerID)-1)
typedef std::function<void(Event*)> EventCallback;
typedef std::function<void(TimerID)> TimerCallback;
struct Event {
hevent_t event;
EventCallback cb;
Event(EventCallback cb = NULL) {
memset(&event, 0, sizeof(hevent_t));
this->cb = std::move(cb);
}
};
struct Timer {
htimer_t* timer;
TimerCallback cb;
uint32_t repeat;
Timer(htimer_t* timer = NULL, TimerCallback cb = NULL, uint32_t repeat = INFINITE) {
this->timer = timer;
this->cb = std::move(cb);
this->repeat = repeat;
}
};
typedef std::shared_ptr<Event> EventPtr;
typedef std::shared_ptr<Timer> TimerPtr;
}
#endif // HV_EVENT_HPP_

View File

@ -0,0 +1,263 @@
#ifndef HV_EVENT_LOOP_HPP_
#define HV_EVENT_LOOP_HPP_
#include <functional>
#include <queue>
#include <map>
#include <mutex>
#include "hloop.h"
#include "hthread.h"
#include "Status.h"
#include "Event.h"
#include "ThreadLocalStorage.h"
namespace hv {
class EventLoop : public Status {
public:
typedef std::function<void()> Functor;
// New an EventLoop using an existing hloop_t object,
// so we can embed an EventLoop object into the old application based on hloop.
// NOTE: Be careful to deal with destroy of hloop_t.
EventLoop(hloop_t* loop = NULL) {
setStatus(kInitializing);
if (loop) {
loop_ = loop;
is_loop_owner = false;
} else {
loop_ = hloop_new(HLOOP_FLAG_AUTO_FREE);
is_loop_owner = true;
}
connectionNum = 0;
setStatus(kInitialized);
}
~EventLoop() {
stop();
}
hloop_t* loop() {
return loop_;
}
// @brief Run loop forever
void run() {
if (loop_ == NULL) return;
if (status() == kRunning) return;
ThreadLocalStorage::set(ThreadLocalStorage::EVENT_LOOP, this);
setStatus(kRunning);
hloop_run(loop_);
setStatus(kStopped);
}
// stop thread-safe
void stop() {
if (loop_ == NULL) return;
if (status() < kRunning) {
if (is_loop_owner) {
hloop_free(&loop_);
}
loop_ = NULL;
return;
}
setStatus(kStopping);
hloop_stop(loop_);
loop_ = NULL;
}
void pause() {
if (loop_ == NULL) return;
if (isRunning()) {
hloop_pause(loop_);
setStatus(kPause);
}
}
void resume() {
if (loop_ == NULL) return;
if (isPause()) {
hloop_resume(loop_);
setStatus(kRunning);
}
}
// Timer interfaces: setTimer, killTimer, resetTimer
TimerID setTimer(int timeout_ms, TimerCallback cb, uint32_t repeat = INFINITE, TimerID timerID = INVALID_TIMER_ID) {
if (loop_ == NULL) return INVALID_TIMER_ID;
htimer_t* htimer = htimer_add(loop_, onTimer, timeout_ms, repeat);
if (timerID == INVALID_TIMER_ID) {
timerID = hevent_id(htimer);
} else {
hevent_set_id(htimer, timerID);
}
TimerPtr timer = std::make_shared<Timer>(htimer, cb, repeat);
hevent_set_userdata(htimer, this);
mutex_.lock();
timers[timerID] = std::move(timer);
mutex_.unlock();
return timerID;
}
// alias javascript setTimeout, setInterval
TimerID setTimeout(int timeout_ms, TimerCallback cb) {
return setTimer(timeout_ms, cb, 1);
}
TimerID setInterval(int interval_ms, TimerCallback cb) {
return setTimer(interval_ms, cb, INFINITE);
}
void killTimer(TimerID timerID) {
std::lock_guard<std::mutex> locker(mutex_);
auto iter = timers.find(timerID);
if (iter != timers.end()) {
htimer_del(iter->second->timer);
timers.erase(iter);
}
}
void resetTimer(TimerID timerID) {
std::lock_guard<std::mutex> locker(mutex_);
auto iter = timers.find(timerID);
if (iter != timers.end()) {
htimer_reset(iter->second->timer);
if (iter->second->repeat == 0) {
iter->second->repeat = 1;
}
}
}
long tid() {
if (loop_ == NULL) return hv_gettid();
return hloop_tid(loop_);
}
bool isInLoopThread() {
if (loop_ == NULL) return false;
return hv_gettid() == hloop_tid(loop_);
}
void assertInLoopThread() {
assert(isInLoopThread());
}
void runInLoop(Functor fn) {
if (isRunning() && isInLoopThread()) {
if (fn) fn();
} else {
queueInLoop(std::move(fn));
}
}
void queueInLoop(Functor fn) {
postEvent([fn](Event* ev) {
if (fn) fn();
});
}
void postEvent(EventCallback cb) {
if (loop_ == NULL) return;
EventPtr ev(new Event(cb));
hevent_set_userdata(&ev->event, this);
ev->event.cb = onCustomEvent;
mutex_.lock();
customEvents.push(ev);
mutex_.unlock();
hloop_post_event(loop_, &ev->event);
}
private:
static void onTimer(htimer_t* htimer) {
EventLoop* loop = (EventLoop*)hevent_userdata(htimer);
TimerID timerID = hevent_id(htimer);
TimerPtr timer = NULL;
loop->mutex_.lock();
auto iter = loop->timers.find(timerID);
if (iter != loop->timers.end()) {
timer = iter->second;
if (timer->repeat != INFINITE) --timer->repeat;
}
loop->mutex_.unlock();
if (timer) {
if (timer->cb) timer->cb(timerID);
if (timer->repeat == 0) {
// htimer_t alloc and free by hloop, but timers[timerID] managed by EventLoop.
loop->mutex_.lock();
loop->timers.erase(timerID);
loop->mutex_.unlock();
}
}
}
static void onCustomEvent(hevent_t* hev) {
EventLoop* loop = (EventLoop*)hevent_userdata(hev);
loop->mutex_.lock();
EventPtr ev = loop->customEvents.front();
loop->customEvents.pop();
loop->mutex_.unlock();
if (ev && ev->cb) ev->cb(ev.get());
}
public:
std::atomic<uint32_t> connectionNum; // for LB_LeastConnections
private:
hloop_t* loop_;
bool is_loop_owner;
std::mutex mutex_;
std::queue<EventPtr> customEvents; // GUAREDE_BY(mutex_)
std::map<TimerID, TimerPtr> timers; // GUAREDE_BY(mutex_)
};
typedef std::shared_ptr<EventLoop> EventLoopPtr;
// ThreadLocalStorage
static inline EventLoop* tlsEventLoop() {
return (EventLoop*)ThreadLocalStorage::get(ThreadLocalStorage::EVENT_LOOP);
}
#define currentThreadEventLoop tlsEventLoop()
static inline TimerID setTimer(int timeout_ms, TimerCallback cb, uint32_t repeat = INFINITE) {
EventLoop* loop = tlsEventLoop();
assert(loop != NULL);
if (loop == NULL) return INVALID_TIMER_ID;
return loop->setTimer(timeout_ms, cb, repeat);
}
static inline void killTimer(TimerID timerID) {
EventLoop* loop = tlsEventLoop();
assert(loop != NULL);
if (loop == NULL) return;
loop->killTimer(timerID);
}
static inline void resetTimer(TimerID timerID) {
EventLoop* loop = tlsEventLoop();
assert(loop != NULL);
if (loop == NULL) return;
loop->resetTimer(timerID);
}
static inline TimerID setTimeout(int timeout_ms, TimerCallback cb) {
return setTimer(timeout_ms, cb, 1);
}
static inline TimerID setInterval(int interval_ms, TimerCallback cb) {
return setTimer(interval_ms, cb, INFINITE);
}
}
#endif // HV_EVENT_LOOP_HPP_

View File

@ -0,0 +1,121 @@
#ifndef HV_EVENT_LOOP_THREAD_HPP_
#define HV_EVENT_LOOP_THREAD_HPP_
#include <thread>
#include "hlog.h"
#include "EventLoop.h"
namespace hv {
class EventLoopThread : public Status {
public:
// Return 0 means OK, other failed.
typedef std::function<int()> Functor;
EventLoopThread(EventLoopPtr loop = NULL) {
setStatus(kInitializing);
if (loop) {
loop_ = loop;
} else {
loop_.reset(new EventLoop);
}
setStatus(kInitialized);
}
~EventLoopThread() {
stop();
join();
}
const EventLoopPtr& loop() {
return loop_;
}
hloop_t* hloop() {
return loop_->loop();
}
bool isRunning() {
return loop_->isRunning();
}
// @param wait_thread_started: if ture this method will block until loop_thread started.
// @param pre: This functor will be executed when loop_thread started.
// @param post:This Functor will be executed when loop_thread stopped.
void start(bool wait_thread_started = true,
Functor pre = Functor(),
Functor post = Functor()) {
if (status() >= kStarting && status() < kStopped) return;
setStatus(kStarting);
thread_.reset(new std::thread(&EventLoopThread::loop_thread, this, pre, post));
if (wait_thread_started) {
while (loop_->status() < kRunning) {
hv_delay(1);
}
}
}
// @param wait_thread_started: if ture this method will block until loop_thread stopped.
// stop thread-safe
void stop(bool wait_thread_stopped = false) {
if (status() < kStarting || status() >= kStopping) return;
setStatus(kStopping);
long loop_tid = loop_->tid();
loop_->stop();
if (wait_thread_stopped) {
if (hv_gettid() == loop_tid) return;
while (!isStopped()) {
hv_delay(1);
}
}
}
// @brief join loop_thread
// @note destructor will join loop_thread if you forget to call this method.
void join() {
if (thread_ && thread_->joinable()) {
thread_->join();
thread_ = NULL;
}
}
private:
void loop_thread(const Functor& pre, const Functor& post) {
hlogi("EventLoopThread started, tid=%ld", hv_gettid());
setStatus(kStarted);
if (pre) {
loop_->queueInLoop([this, pre]{
if (pre() != 0) {
loop_->stop();
}
});
}
loop_->run();
assert(loop_->isStopped());
if (post) {
post();
}
setStatus(kStopped);
hlogi("EventLoopThread stopped, tid=%ld", hv_gettid());
}
private:
EventLoopPtr loop_;
std::shared_ptr<std::thread> thread_;
};
typedef std::shared_ptr<EventLoopThread> EventLoopThreadPtr;
}
#endif // HV_EVENT_LOOP_THREAD_HPP_

View File

@ -0,0 +1,140 @@
#ifndef HV_EVENT_LOOP_THREAD_POOL_HPP_
#define HV_EVENT_LOOP_THREAD_POOL_HPP_
#include "EventLoopThread.h"
#include "hbase.h"
namespace hv {
class EventLoopThreadPool : public Status {
public:
EventLoopThreadPool(int thread_num = std::thread::hardware_concurrency()) {
setStatus(kInitializing);
thread_num_ = thread_num;
next_loop_idx_ = 0;
setStatus(kInitialized);
}
~EventLoopThreadPool() {
stop();
join();
}
int threadNum() {
return thread_num_;
}
void setThreadNum(int num) {
thread_num_ = num;
}
EventLoopPtr nextLoop(load_balance_e lb = LB_RoundRobin) {
int numLoops = loop_threads_.size();
if (numLoops == 0) return NULL;
int idx = 0;
if (lb == LB_RoundRobin) {
if (++next_loop_idx_ >= numLoops) next_loop_idx_ = 0;
idx = next_loop_idx_;
} else if (lb == LB_Random) {
idx = hv_rand(0, numLoops - 1);
} else if (lb == LB_LeastConnections) {
for (int i = 1; i < numLoops; ++i) {
if (loop_threads_[i]->loop()->connectionNum < loop_threads_[idx]->loop()->connectionNum) {
idx = i;
}
}
} else {
// Not Implemented
}
return loop_threads_[idx]->loop();
}
EventLoopPtr loop(int idx = -1) {
if (idx >= 0 && idx < loop_threads_.size()) {
return loop_threads_[idx]->loop();
}
return nextLoop();
}
hloop_t* hloop(int idx = -1) {
EventLoopPtr ptr = loop(idx);
return ptr ? ptr->loop() : NULL;
}
// @param wait_threads_started: if ture this method will block until all loop_threads started.
// @param pre: This functor will be executed when loop_thread started.
// @param post:This Functor will be executed when loop_thread stopped.
void start(bool wait_threads_started = false,
std::function<void(const EventLoopPtr&)> pre = NULL,
std::function<void(const EventLoopPtr&)> post = NULL) {
if (thread_num_ == 0) return;
if (status() >= kStarting && status() < kStopped) return;
setStatus(kStarting);
std::shared_ptr<std::atomic<int>> started_cnt(new std::atomic<int>(0));
std::shared_ptr<std::atomic<int>> exited_cnt(new std::atomic<int>(0));
loop_threads_.clear();
for (int i = 0; i < thread_num_; ++i) {
EventLoopThreadPtr loop_thread(new EventLoopThread);
const EventLoopPtr& loop = loop_thread->loop();
loop_thread->start(false,
[this, started_cnt, pre, &loop]() {
if (++(*started_cnt) == thread_num_) {
setStatus(kRunning);
}
if (pre) pre(loop);
return 0;
},
[this, exited_cnt, post, &loop]() {
if (post) post(loop);
if (++(*exited_cnt) == thread_num_) {
setStatus(kStopped);
}
return 0;
}
);
loop_threads_.push_back(loop_thread);
}
if (wait_threads_started) {
while (status() < kRunning) {
hv_delay(1);
}
}
}
// @param wait_threads_started: if ture this method will block until all loop_threads stopped.
// stop thread-safe
void stop(bool wait_threads_stopped = false) {
if (status() < kStarting || status() >= kStopping) return;
setStatus(kStopping);
for (auto& loop_thread : loop_threads_) {
loop_thread->stop(false);
}
if (wait_threads_stopped) {
while (!isStopped()) {
hv_delay(1);
}
}
}
// @brief join all loop_threads
// @note destructor will join loop_threads if you forget to call this method.
void join() {
for (auto& loop_thread : loop_threads_) {
loop_thread->join();
}
}
private:
int thread_num_;
std::vector<EventLoopThreadPtr> loop_threads_;
std::atomic<unsigned int> next_loop_idx_;
};
}
#endif // HV_EVENT_LOOP_THREAD_POOL_HPP_

View File

@ -0,0 +1,193 @@
#ifndef HV_HTTP_CONTEXT_H_
#define HV_HTTP_CONTEXT_H_
#include "hexport.h"
#include "HttpMessage.h"
#include "HttpResponseWriter.h"
namespace hv {
struct HttpService;
struct HV_EXPORT HttpContext {
HttpService* service;
HttpRequestPtr request;
HttpResponsePtr response;
HttpResponseWriterPtr writer;
// HttpRequest aliases
// return request->xxx
std::string ip() {
return request->client_addr.ip;
}
http_method method() {
return request->method;
}
std::string url() {
return request->url;
}
std::string path() {
return request->Path();
}
std::string fullpath() {
return request->FullPath();
}
std::string host() {
return request->Host();
}
const http_headers& headers() {
return request->headers;
}
std::string header(const char* key, const std::string& defvalue = hv::empty_string) {
return request->GetHeader(key, defvalue);
}
const hv::QueryParams& params() {
return request->query_params;
}
std::string param(const char* key, const std::string& defvalue = hv::empty_string) {
return request->GetParam(key, defvalue);
}
const HttpCookie& cookie(const char* name) {
return request->GetCookie(name);
}
int length() {
return request->ContentLength();
}
http_content_type type() {
return request->ContentType();
}
bool is(http_content_type content_type) {
return request->ContentType() == content_type;
}
bool is(const char* content_type) {
return request->ContentType() == http_content_type_enum(content_type);
}
std::string& body() {
return request->body;
}
#ifndef WITHOUT_HTTP_CONTENT
// Content-Type: application/json
const hv::Json& json() {
return request->GetJson();
}
// Content-Type: multipart/form-data
const hv::MultiPart& form() {
return request->GetForm();
}
std::string form(const char* name, const std::string& defvalue = hv::empty_string) {
return request->GetFormData(name, defvalue);
}
// Content-Type: application/x-www-form-urlencoded
const hv::KeyValue& urlencoded() {
return request->GetUrlEncoded();
}
std::string urlencoded(const char* key, const std::string& defvalue = hv::empty_string) {
return request->GetUrlEncoded(key, defvalue);
}
// T=[bool, int, int64_t, float, double]
template<typename T>
T get(const char* key, T defvalue = 0) {
return request->Get(key, defvalue);
}
std::string get(const char* key, const std::string& defvalue = hv::empty_string) {
return request->GetString(key, defvalue);
}
#endif
// HttpResponse aliases
// response->xxx = xxx
void setStatus(http_status status) {
response->status_code = status;
}
void setContentType(http_content_type type) {
response->content_type = type;
}
void setContentType(const char* type) {
response->content_type = http_content_type_enum(type);
}
void setHeader(const char* key, const std::string& value) {
response->headers[key] = value;
if (stricmp(key, "Content-Type") == 0) {
setContentType(value.c_str());
}
}
void setCookie(const HttpCookie& cookie) {
response->AddCookie(cookie);
}
void setBody(const std::string& body) {
response->body = body;
}
// response->sendXxx
int send() {
writer->End();
return response->status_code;
}
int send(const std::string& str, http_content_type type = APPLICATION_JSON) {
response->content_type = type;
response->body = str;
return send();
}
int sendString(const std::string& str) {
response->String(str);
return send();
}
int sendData(void* data, int len, bool nocopy = true) {
response->Data(data, len, nocopy);
return send();
}
int sendFile(const char* filepath) {
response->File(filepath);
return send();
}
#ifndef WITHOUT_HTTP_CONTENT
// T=[bool, int, int64_t, float, double, string]
template<typename T>
void set(const char* key, const T& value) {
response->Set(key, value);
}
// @see HttpMessage::Json
// @usage https://github.com/nlohmann/json
template<typename T>
int sendJson(const T& t) {
response->Json(t);
return send();
}
#endif
};
} // end namespace hv
typedef std::shared_ptr<hv::HttpContext> HttpContextPtr;
#endif // HV_HTTP_CONTEXT_H_

View File

@ -0,0 +1,561 @@
#ifndef HV_HTTP_MESSAGE_H_
#define HV_HTTP_MESSAGE_H_
/*
* @class HttpMessage
* HttpRequest extends HttpMessage
* HttpResponse extends HttpMessage
*
* @member
* request-line: GET / HTTP/1.1\r\n => method path
* response-line: HTTP/1.1 200 OK\r\n => status_code
* headers, cookies
* body
*
* content, content_length, content_type
* json, form, kv
*
* @function
* Content, ContentLength, ContentType
* ParseUrl, ParseBody
* DumpUrl, DumpHeaders, DumpBody, Dump
* GetHeader, GetParam, GetJson, GetFormData, GetUrlEncoded
* SetHeader, SetParam, SetBody, SetFormData, SetUrlEncoded
* Get<T>, Set<T>
* GetString, GetBool, GetInt, GetFloat
* String, Data, Json, File, FormFile
*
* @example
* examples/http_server_test.cpp
* examples/http_client_test.cpp
* examples/httpd
*
*/
#include <memory>
#include <string>
#include <map>
#include <functional>
#include "hexport.h"
#include "hbase.h"
#include "hstring.h"
#include "hfile.h"
#include "hpath.h"
#include "httpdef.h"
#include "http_content.h"
namespace hv {
struct NetAddr {
std::string ip;
int port;
std::string ipport() {
return hv::asprintf("%s:%d", ip.c_str(), port);
}
};
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
// Cookie: sessionid=1; domain=.example.com; path=/; max-age=86400; secure; httponly
struct HV_EXPORT HttpCookie {
std::string name;
std::string value;
std::string domain;
std::string path;
std::string expires;
int max_age;
bool secure;
bool httponly;
enum SameSite {
Default,
Strict,
Lax,
None
} samesite;
HttpCookie() {
max_age = 0;
secure = false;
httponly = false;
samesite = Default;
}
bool parse(const std::string& str);
std::string dump() const;
};
typedef std::map<std::string, std::string, hv::StringCaseLess> http_headers;
typedef std::vector<HttpCookie> http_cookies;
typedef std::string http_body;
HV_EXPORT extern http_headers DefaultHeaders;
HV_EXPORT extern http_body NoBody;
HV_EXPORT extern HttpCookie NoCookie;
class HV_EXPORT HttpMessage {
public:
static char s_date[32];
int type;
unsigned short http_major;
unsigned short http_minor;
http_headers headers;
http_cookies cookies;
http_body body;
// http_cb
std::function<void(HttpMessage*, http_parser_state state, const char* data, size_t size)> http_cb;
// structured content
void* content; // DATA_NO_COPY
size_t content_length;
http_content_type content_type;
#ifndef WITHOUT_HTTP_CONTENT
hv::Json json; // APPLICATION_JSON
hv::MultiPart form; // MULTIPART_FORM_DATA
hv::KeyValue kv; // X_WWW_FORM_URLENCODED
// T=[bool, int, int64_t, float, double]
template<typename T>
T Get(const char* key, T defvalue = 0);
std::string GetString(const char* key, const std::string& = "");
bool GetBool(const char* key, bool defvalue = 0);
int64_t GetInt(const char* key, int64_t defvalue = 0);
double GetFloat(const char* key, double defvalue = 0);
template<typename T>
void Set(const char* key, const T& value) {
switch (ContentType()) {
case APPLICATION_JSON:
json[key] = value;
break;
case MULTIPART_FORM_DATA:
form[key] = hv::FormData(value);
break;
case X_WWW_FORM_URLENCODED:
kv[key] = hv::to_string(value);
break;
default:
break;
}
}
/*
* @usage https://github.com/nlohmann/json
*
* null: Json(nullptr);
* boolean: Json(true);
* number: Json(123);
* string: Json("hello");
* object: Json(std::map<string, ValueType>);
* Json(hv::Json::object({
{"k1", "v1"},
{"k2", "v2"}
}));
* array: Json(std::vector<ValueType>);
Json(hv::Json::array(
{1, 2, 3}
));
*/
// Content-Type: application/json
template<typename T>
int Json(const T& t) {
content_type = APPLICATION_JSON;
hv::Json j(t);
body = j.dump(2);
return 200;
}
const hv::Json& GetJson() {
if (json.empty() && ContentType() == APPLICATION_JSON) {
ParseBody();
}
return json;
}
// Content-Type: multipart/form-data
template<typename T>
void SetFormData(const char* name, const T& t) {
form[name] = hv::FormData(t);
}
void SetFormFile(const char* name, const char* filepath) {
form[name] = hv::FormData(NULL, filepath);
}
int FormFile(const char* name, const char* filepath) {
content_type = MULTIPART_FORM_DATA;
form[name] = hv::FormData(NULL, filepath);
return 200;
}
const hv::MultiPart& GetForm() {
if (form.empty() && ContentType() == MULTIPART_FORM_DATA) {
ParseBody();
}
return form;
}
std::string GetFormData(const char* name, const std::string& defvalue = hv::empty_string) {
if (form.empty() && ContentType() == MULTIPART_FORM_DATA) {
ParseBody();
}
auto iter = form.find(name);
return iter == form.end() ? defvalue : iter->second.content;
}
int SaveFormFile(const char* name, const char* path) {
if (ContentType() != MULTIPART_FORM_DATA) {
return HTTP_STATUS_BAD_REQUEST;
}
if (form.empty()) {
ParseBody();
if (form.empty()) return HTTP_STATUS_BAD_REQUEST;
}
const hv::FormData& formdata = form[name];
if (formdata.content.empty()) {
return HTTP_STATUS_BAD_REQUEST;
}
std::string filepath(path);
if (HPath::isdir(path)) {
filepath = HPath::join(filepath, formdata.filename);
}
HFile file;
if (file.open(filepath.c_str(), "wb") != 0) {
return HTTP_STATUS_INTERNAL_SERVER_ERROR;
}
file.write(formdata.content.data(), formdata.content.size());
return 200;
}
// Content-Type: application/x-www-form-urlencoded
template<typename T>
void SetUrlEncoded(const char* key, const T& t) {
kv[key] = hv::to_string(t);
}
const hv::KeyValue& GetUrlEncoded() {
if (kv.empty() && ContentType() == X_WWW_FORM_URLENCODED) {
ParseBody();
}
return kv;
}
std::string GetUrlEncoded(const char* key, const std::string& defvalue = hv::empty_string) {
if (kv.empty() && ContentType() == X_WWW_FORM_URLENCODED) {
ParseBody();
}
auto iter = kv.find(key);
return iter == kv.end() ? defvalue : iter->second;
}
#endif
HttpMessage() {
type = HTTP_BOTH;
Init();
}
virtual ~HttpMessage() {}
void Init() {
http_major = 1;
http_minor = 1;
content = NULL;
content_length = 0;
content_type = CONTENT_TYPE_NONE;
}
virtual void Reset() {
Init();
headers.clear();
cookies.clear();
body.clear();
#ifndef WITHOUT_HTTP_CONTENT
json.clear();
form.clear();
kv.clear();
#endif
}
// structured-content -> content_type <-> headers Content-Type
void FillContentType();
// body.size -> content_length <-> headers Content-Length
void FillContentLength();
bool IsChunked();
bool IsKeepAlive();
// headers
void SetHeader(const char* key, const std::string& value) {
headers[key] = value;
}
std::string GetHeader(const char* key, const std::string& defvalue = hv::empty_string) {
auto iter = headers.find(key);
return iter == headers.end() ? defvalue : iter->second;
}
// body
void SetBody(const std::string& body) {
this->body = body;
}
const std::string& Body() {
return this->body;
}
// headers -> string
void DumpHeaders(std::string& str);
// structured content -> body
void DumpBody();
void DumpBody(std::string& str);
// body -> structured content
// @retval 0:succeed
int ParseBody();
virtual std::string Dump(bool is_dump_headers, bool is_dump_body);
void* Content() {
if (content == NULL && body.size() != 0) {
content = (void*)body.data();
}
return content;
}
size_t ContentLength() {
if (content_length == 0) {
FillContentLength();
}
return content_length;
}
http_content_type ContentType() {
if (content_type == CONTENT_TYPE_NONE) {
FillContentType();
}
return content_type;
}
void SetContentTypeByFilename(const char* filepath) {
const char* suffix = hv_suffixname(filepath);
if (suffix) {
content_type = http_content_type_enum_by_suffix(suffix);
}
if (content_type == CONTENT_TYPE_NONE || content_type == CONTENT_TYPE_UNDEFINED) {
content_type = APPLICATION_OCTET_STREAM;
}
}
void AddCookie(const HttpCookie& cookie) {
cookies.push_back(cookie);
}
const HttpCookie& GetCookie(const std::string& name) {
for (auto iter = cookies.begin(); iter != cookies.end(); ++iter) {
if (iter->name == name) {
return *iter;
}
}
return NoCookie;
}
int String(const std::string& str) {
content_type = TEXT_PLAIN;
body = str;
return 200;
}
int Data(void* data, int len, bool nocopy = true) {
content_type = APPLICATION_OCTET_STREAM;
if (nocopy) {
content = data;
content_length = len;
} else {
content_length = body.size();
body.resize(content_length + len);
memcpy((void*)(body.data() + content_length), data, len);
content_length += len;
}
return 200;
}
int File(const char* filepath) {
HFile file;
if (file.open(filepath, "rb") != 0) {
return HTTP_STATUS_NOT_FOUND;
}
SetContentTypeByFilename(filepath);
file.readall(body);
return 200;
}
int SaveFile(const char* filepath) {
HFile file;
if (file.open(filepath, "wb") != 0) {
return HTTP_STATUS_NOT_FOUND;
}
file.write(body.data(), body.size());
return 200;
}
};
#define DEFAULT_HTTP_USER_AGENT "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
#define DEFAULT_HTTP_TIMEOUT 60 // s
#define DEFAULT_HTTP_CONNECT_TIMEOUT 10 // s
#define DEFAULT_HTTP_FAIL_RETRY_COUNT 1
#define DEFAULT_HTTP_FAIL_RETRY_DELAY 1000 // ms
class HV_EXPORT HttpRequest : public HttpMessage {
public:
http_method method;
// scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
std::string url;
// structured url
std::string scheme;
std::string host;
int port;
std::string path;
hv::QueryParams query_params;
// client_addr
hv::NetAddr client_addr; // for http server save client addr of request
// for HttpClient
uint16_t timeout; // unit: s
uint16_t connect_timeout;// unit: s
uint32_t retry_count; // just for AsyncHttpClient fail retry
uint32_t retry_delay; // just for AsyncHttpClient fail retry
unsigned redirect: 1;
unsigned proxy : 1;
HttpRequest() : HttpMessage() {
type = HTTP_REQUEST;
Init();
}
void Init() {
headers["User-Agent"] = DEFAULT_HTTP_USER_AGENT;
headers["Accept"] = "*/*";
method = HTTP_GET;
scheme = "http";
host = "127.0.0.1";
port = DEFAULT_HTTP_PORT;
path = "/";
timeout = DEFAULT_HTTP_TIMEOUT;
connect_timeout = DEFAULT_HTTP_CONNECT_TIMEOUT;
retry_count = DEFAULT_HTTP_FAIL_RETRY_COUNT;
retry_delay = DEFAULT_HTTP_FAIL_RETRY_DELAY;
redirect = 1;
proxy = 0;
}
virtual void Reset() {
HttpMessage::Reset();
Init();
url.clear();
query_params.clear();
}
virtual std::string Dump(bool is_dump_headers = true, bool is_dump_body = false);
// method
void SetMethod(const char* method) {
this->method = http_method_enum(method);
}
const char* Method() {
return http_method_str(method);
}
// scheme
bool IsHttps() {
return strncmp(scheme.c_str(), "https", 5) == 0 ||
strncmp(url.c_str(), "https://", 8) == 0;
}
// url
void SetUrl(const char* url) {
this->url = url;
}
const std::string& Url() {
return url;
}
// structed url -> url
void DumpUrl();
// url -> structed url
void ParseUrl();
// /path?query#fragment
std::string FullPath() { return path; }
// /path
std::string Path();
// ?query_params
template<typename T>
void SetParam(const char* key, const T& t) {
query_params[key] = hv::to_string(t);
}
std::string GetParam(const char* key, const std::string& defvalue = hv::empty_string) {
auto iter = query_params.find(key);
return iter == query_params.end() ? defvalue : iter->second;
}
// Host:
std::string Host() {
auto iter = headers.find("Host");
return iter == headers.end() ? host : iter->second;
}
void FillHost(const char* host, int port = DEFAULT_HTTP_PORT);
void SetHost(const char* host, int port = DEFAULT_HTTP_PORT);
void SetProxy(const char* host, int port);
bool IsProxy() { return proxy; }
// Range: bytes=0-4095
void SetRange(long from = 0, long to = -1) {
headers["Range"] = hv::asprintf("bytes=%ld-%ld", from, to);
}
bool GetRange(long& from, long& to) {
auto iter = headers.find("Range");
if (iter != headers.end()) {
sscanf(iter->second.c_str(), "bytes=%ld-%ld", &from, &to);
return true;
}
from = to = 0;
return false;
}
};
class HV_EXPORT HttpResponse : public HttpMessage {
public:
http_status status_code;
const char* status_message() {
return http_status_str(status_code);
}
HttpResponse() : HttpMessage() {
type = HTTP_RESPONSE;
Init();
}
void Init() {
status_code = HTTP_STATUS_OK;
}
virtual void Reset() {
HttpMessage::Reset();
Init();
}
virtual std::string Dump(bool is_dump_headers = true, bool is_dump_body = false);
// Content-Range: bytes 0-4095/10240000
void SetRange(long from, long to, long total) {
headers["Content-Range"] = hv::asprintf("bytes %ld-%ld/%ld", from, to, total);
}
bool GetRange(long& from, long& to, long& total) {
auto iter = headers.find("Content-Range");
if (iter != headers.end()) {
sscanf(iter->second.c_str(), "bytes %ld-%ld/%ld", &from, &to, &total);
return true;
}
from = to = total = 0;
return false;
}
};
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
typedef std::shared_ptr<HttpResponse> HttpResponsePtr;
typedef std::function<void(const HttpResponsePtr&)> HttpResponseCallback;
#endif // HV_HTTP_MESSAGE_H_

View File

@ -0,0 +1,51 @@
#ifndef HV_HTTP_PARSER_H_
#define HV_HTTP_PARSER_H_
#include "hexport.h"
#include "HttpMessage.h"
class HV_EXPORT HttpParser {
public:
http_version version;
http_session_type type;
static HttpParser* New(http_session_type type = HTTP_CLIENT, http_version version = HTTP_V1);
virtual ~HttpParser() {}
virtual int GetSendData(char** data, size_t* len) = 0;
virtual int FeedRecvData(const char* data, size_t len) = 0;
// Http1Parser: http_parser_state
// Http2Parser: http2_session_state
virtual int GetState() = 0;
// Http1Parser: GetState() != HP_MESSAGE_COMPLETE
// Http2Parser: GetState() == H2_WANT_RECV
virtual bool WantRecv() = 0;
// Http1Parser: GetState() == HP_MESSAGE_COMPLETE
// Http2Parser: GetState() == H2_WANT_SEND
virtual bool WantSend() = 0;
// IsComplete: Is recved HttpRequest or HttpResponse complete?
// Http1Parser: GetState() == HP_MESSAGE_COMPLETE
// Http2Parser: (state == H2_RECV_HEADERS || state == H2_RECV_DATA) && stream_closed
virtual bool IsComplete() = 0;
// client
// SubmitRequest -> while(GetSendData) {send} -> InitResponse -> do {recv -> FeedRecvData} while(WantRecv)
virtual int SubmitRequest(HttpRequest* req) = 0;
virtual int InitResponse(HttpResponse* res) = 0;
// server
// InitRequest -> do {recv -> FeedRecvData} while(WantRecv) -> SubmitResponse -> while(GetSendData) {send}
virtual int InitRequest(HttpRequest* req) = 0;
virtual int SubmitResponse(HttpResponse* res) = 0;
virtual int GetError() = 0;
virtual const char* StrError(int error) = 0;
};
typedef std::shared_ptr<HttpParser> HttpParserPtr;
#endif // HV_HTTP_PARSER_H_

View File

@ -0,0 +1,177 @@
#ifndef HV_HTTP_RESPONSE_WRITER_H_
#define HV_HTTP_RESPONSE_WRITER_H_
#include "Channel.h"
#include "HttpMessage.h"
namespace hv {
class HttpResponseWriter : public SocketChannel {
public:
HttpResponsePtr response;
enum State {
SEND_BEGIN,
SEND_HEADER,
SEND_BODY,
SEND_CHUNKED,
SEND_CHUNKED_END,
SEND_END,
} state;
HttpResponseWriter(hio_t* io, const HttpResponsePtr& resp)
: SocketChannel(io)
, response(resp)
, state(SEND_BEGIN)
{}
~HttpResponseWriter() {}
// Begin -> End
// Begin -> WriteResponse -> End
// Begin -> WriteStatus -> WriteHeader -> WriteBody -> End
// Begin -> EndHeaders("Content-Type", "text/event-stream") -> write -> write -> ... -> close
// Begin -> EndHeaders("Content-Length", content_length) -> WriteBody -> WriteBody -> ... -> End
// Begin -> EndHeaders("Transfer-Encoding", "chunked") -> WriteChunked -> WriteChunked -> ... -> End
int Begin() {
state = SEND_BEGIN;
return 0;
}
int WriteStatus(http_status status_codes) {
response->status_code = status_codes;
return 0;
}
int WriteHeader(const char* key, const char* value) {
response->headers[key] = value;
return 0;
}
template<typename T>
int WriteHeader(const char* key, T num) {
response->headers[key] = hv::to_string(num);
return 0;
}
int EndHeaders(const char* key = NULL, const char* value = NULL) {
if (state != SEND_BEGIN) return -1;
if (key && value) {
response->headers[key] = value;
}
std::string headers = response->Dump(true, false);
state = SEND_HEADER;
return write(headers);
}
template<typename T>
int EndHeaders(const char* key, T num) {
std::string value = hv::to_string(num);
return EndHeaders(key, value.c_str());
}
int WriteChunked(const char* buf, int len = -1) {
int ret = 0;
if (len == -1) len = strlen(buf);
if (state == SEND_BEGIN) {
EndHeaders("Transfer-Encoding", "chunked");
}
char chunked_header[64];
int chunked_header_len = snprintf(chunked_header, sizeof(chunked_header), "%x\r\n", len);
write(chunked_header, chunked_header_len);
if (buf && len) {
ret = write(buf, len);
state = SEND_CHUNKED;
} else {
state = SEND_CHUNKED_END;
}
write("\r\n", 2);
return ret;
}
int WriteChunked(const std::string& str) {
return WriteChunked(str.c_str(), str.size());
}
int EndChunked() {
return WriteChunked(NULL, 0);
}
int WriteBody(const char* buf, int len = -1) {
if (response->IsChunked()) {
return WriteChunked(buf, len);
}
if (len == -1) len = strlen(buf);
if (state == SEND_BEGIN) {
response->body.append(buf, len);
return len;
} else {
state = SEND_BODY;
return write(buf, len);
}
}
int WriteBody(const std::string& str) {
return WriteBody(str.c_str(), str.size());
}
int WriteResponse(HttpResponse* resp) {
if (resp == NULL) {
response->status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
return 0;
}
bool is_dump_headers = state == SEND_BEGIN ? true : false;
std::string msg = resp->Dump(is_dump_headers, true);
state = SEND_BODY;
return write(msg);
}
int End(const char* buf = NULL, int len = -1) {
if (state == SEND_END) return 0;
if (!isConnected()) {
state = SEND_END;
return -1;
}
int ret = 0;
if (state == SEND_CHUNKED) {
if (buf) {
ret = WriteChunked(buf, len);
}
if (state == SEND_CHUNKED) {
EndChunked();
}
} else {
if (buf) {
ret = WriteBody(buf, len);
}
bool is_dump_headers = true;
bool is_dump_body = true;
if (state == SEND_HEADER) {
is_dump_headers = false;
} else if (state == SEND_BODY) {
is_dump_headers = false;
is_dump_body = false;
}
if (is_dump_body) {
std::string msg = response->Dump(is_dump_headers, is_dump_body);
ret = write(msg);
}
}
state = SEND_END;
if (!response->IsKeepAlive()) {
close(true);
}
return ret;
}
int End(const std::string& str) {
return End(str.c_str(), str.size());
}
};
}
typedef std::shared_ptr<hv::HttpResponseWriter> HttpResponseWriterPtr;
#endif // HV_HTTP_RESPONSE_WRITER_H_

View File

@ -0,0 +1,116 @@
#ifndef HV_HTTP_SERVER_H_
#define HV_HTTP_SERVER_H_
#include "hexport.h"
#include "HttpService.h"
// #include "WebSocketServer.h"
namespace hv {
struct WebSocketService;
}
using hv::HttpService;
using hv::WebSocketService;
typedef struct http_server_s {
char host[64];
int port; // http_port
int https_port;
int http_version;
int worker_processes;
int worker_threads;
HttpService* service; // http service
WebSocketService* ws; // websocket service
void* userdata;
//private:
int listenfd[2]; // 0: http, 1: https
void* privdata;
#ifdef __cplusplus
http_server_s() {
strcpy(host, "0.0.0.0");
// port = DEFAULT_HTTP_PORT;
// https_port = DEFAULT_HTTPS_PORT;
// port = 8080;
// https_port = 8443;
port = https_port = 0;
http_version = 1;
worker_processes = 0;
worker_threads = 0;
service = NULL;
ws = NULL;
listenfd[0] = listenfd[1] = -1;
userdata = NULL;
privdata = NULL;
}
#endif
} http_server_t;
// @param wait: Whether to occupy current thread
HV_EXPORT int http_server_run(http_server_t* server, int wait = 1);
// NOTE: stop all loops and join all threads
HV_EXPORT int http_server_stop(http_server_t* server);
/*
#include "HttpServer.h"
using namespace hv;
int main() {
HttpService service;
service.GET("/ping", [](HttpRequest* req, HttpResponse* resp) {
resp->body = "pong";
return 200;
});
HttpServer server;
server.registerHttpService(&service);
server.setPort(8080);
server.setThreadNum(4);
server.run();
return 0;
}
*/
namespace hv {
class HttpServer : public http_server_t {
public:
HttpServer() : http_server_t() {}
~HttpServer() { stop(); }
void registerHttpService(HttpService* service) {
this->service = service;
}
void setHost(const char* host = "0.0.0.0") {
if (host) strcpy(this->host, host);
}
void setPort(int port = 0, int ssl_port = 0) {
if (port != 0) this->port = port;
if (ssl_port != 0) this->https_port = ssl_port;
}
void setProcessNum(int num) {
this->worker_processes = num;
}
void setThreadNum(int num) {
this->worker_threads = num;
}
int run(bool wait = true) {
return http_server_run(this, wait);
}
int start() {
return run(false);
}
int stop() {
return http_server_stop(this);
}
};
}
#endif // HV_HTTP_SERVER_H_

View File

@ -0,0 +1,266 @@
#ifndef HV_HTTP_SERVICE_H_
#define HV_HTTP_SERVICE_H_
#include <string>
#include <map>
#include <unordered_map>
#include <list>
#include <memory>
#include <functional>
#include "hexport.h"
#include "HttpMessage.h"
#include "HttpResponseWriter.h"
#include "HttpContext.h"
#define DEFAULT_BASE_URL "/api/v1"
#define DEFAULT_DOCUMENT_ROOT "/var/www/html"
#define DEFAULT_HOME_PAGE "index.html"
#define DEFAULT_ERROR_PAGE "error.html"
#define DEFAULT_INDEXOF_DIR "/downloads/"
#define DEFAULT_KEEPALIVE_TIMEOUT 75000 // ms
// for FileCache
#define MAX_FILE_CACHE_SIZE (1 << 22) // 4M
#define DEFAULT_FILE_CACHE_STAT_INTERVAL 10 // s
#define DEFAULT_FILE_CACHE_EXPIRED_TIME 60 // s
/*
* @param[in] req: parsed structured http request
* @param[out] resp: structured http response
* @return 0: handle unfinished
* http_status_code: handle done
*/
#define HTTP_STATUS_UNFINISHED 0
// NOTE: http_sync_handler run on IO thread
typedef std::function<int(HttpRequest* req, HttpResponse* resp)> http_sync_handler;
// NOTE: http_async_handler run on hv::async threadpool
typedef std::function<void(const HttpRequestPtr& req, const HttpResponseWriterPtr& writer)> http_async_handler;
// NOTE: http_ctx_handler run on IO thread, you can easily post HttpContextPtr to your consumer thread for processing.
typedef std::function<int(const HttpContextPtr& ctx)> http_ctx_handler;
struct http_handler {
http_sync_handler sync_handler;
http_async_handler async_handler;
http_ctx_handler ctx_handler;
http_handler() {}
http_handler(http_sync_handler fn) : sync_handler(std::move(fn)) {}
http_handler(http_async_handler fn) : async_handler(std::move(fn)) {}
http_handler(http_ctx_handler fn) : ctx_handler(std::move(fn)) {}
http_handler(const http_handler& rhs)
: sync_handler(std::move(rhs.sync_handler))
, async_handler(std::move(rhs.async_handler))
, ctx_handler(std::move(rhs.ctx_handler))
{}
const http_handler& operator=(http_sync_handler fn) {
sync_handler = std::move(fn);
return *this;
}
const http_handler& operator=(http_async_handler fn) {
async_handler = std::move(fn);
return *this;
}
const http_handler& operator=(http_ctx_handler fn) {
ctx_handler = std::move(fn);
return *this;
}
bool isNull() {
return sync_handler == NULL &&
async_handler == NULL &&
ctx_handler == NULL;
}
operator bool() {
return !isNull();
}
};
struct http_method_handler {
http_method method;
http_handler handler;
http_method_handler() {}
http_method_handler(http_method m, const http_handler& h) : method(m), handler(h) {}
};
// method => http_method_handler
typedef std::list<http_method_handler> http_method_handlers;
// path => http_method_handlers
typedef std::unordered_map<std::string, std::shared_ptr<http_method_handlers>> http_api_handlers;
namespace hv {
struct HV_EXPORT HttpService {
// preprocessor -> processor -> postprocessor
http_handler preprocessor;
// processor: api_handlers -> staticHandler -> errorHandler
http_handler processor;
http_handler postprocessor;
// api service (that is http.APIServer)
std::string base_url;
http_api_handlers api_handlers;
// file service (that is http.FileServer)
http_handler staticHandler;
http_handler largeFileHandler;
std::string document_root;
std::string home_page;
std::string error_page;
// indexof service (that is http.DirectoryServer)
std::string index_of;
http_handler errorHandler;
// options
int keepalive_timeout;
int max_file_cache_size; // cache small file
int file_cache_stat_interval; // stat file is modified
int file_cache_expired_time; // remove expired file cache
/*
* @test limit_rate
* @build make examples
* @server bin/httpd -c etc/httpd.conf -s restart -d
* @client bin/wget http://127.0.0.1:8080/downloads/test.zip
*/
int limit_rate; // limit send rate, unit: KB/s
HttpService() {
// base_url = DEFAULT_BASE_URL;
document_root = DEFAULT_DOCUMENT_ROOT;
home_page = DEFAULT_HOME_PAGE;
// error_page = DEFAULT_ERROR_PAGE;
// index_of = DEFAULT_INDEXOF_DIR;
keepalive_timeout = DEFAULT_KEEPALIVE_TIMEOUT;
max_file_cache_size = MAX_FILE_CACHE_SIZE;
file_cache_stat_interval = DEFAULT_FILE_CACHE_STAT_INTERVAL;
file_cache_expired_time = DEFAULT_FILE_CACHE_EXPIRED_TIME;
limit_rate = -1; // unlimited
}
void AddApi(const char* path, http_method method, const http_handler& handler);
// @retval 0 OK, else HTTP_STATUS_NOT_FOUND, HTTP_STATUS_METHOD_NOT_ALLOWED
int GetApi(const char* url, http_method method, http_handler** handler);
// RESTful API /:field/ => req->query_params["field"]
int GetApi(HttpRequest* req, http_handler** handler);
hv::StringList Paths() {
hv::StringList paths;
for (auto& pair : api_handlers) {
paths.emplace_back(pair.first);
}
return paths;
}
// github.com/gin-gonic/gin
void Handle(const char* httpMethod, const char* relativePath, http_sync_handler handlerFunc) {
AddApi(relativePath, http_method_enum(httpMethod), http_handler(handlerFunc));
}
void Handle(const char* httpMethod, const char* relativePath, http_async_handler handlerFunc) {
AddApi(relativePath, http_method_enum(httpMethod), http_handler(handlerFunc));
}
void Handle(const char* httpMethod, const char* relativePath, http_ctx_handler handlerFunc) {
AddApi(relativePath, http_method_enum(httpMethod), http_handler(handlerFunc));
}
// HEAD
void HEAD(const char* relativePath, http_sync_handler handlerFunc) {
Handle("HEAD", relativePath, handlerFunc);
}
void HEAD(const char* relativePath, http_async_handler handlerFunc) {
Handle("HEAD", relativePath, handlerFunc);
}
void HEAD(const char* relativePath, http_ctx_handler handlerFunc) {
Handle("HEAD", relativePath, handlerFunc);
}
// GET
void GET(const char* relativePath, http_sync_handler handlerFunc) {
Handle("GET", relativePath, handlerFunc);
}
void GET(const char* relativePath, http_async_handler handlerFunc) {
Handle("GET", relativePath, handlerFunc);
}
void GET(const char* relativePath, http_ctx_handler handlerFunc) {
Handle("GET", relativePath, handlerFunc);
}
// POST
void POST(const char* relativePath, http_sync_handler handlerFunc) {
Handle("POST", relativePath, handlerFunc);
}
void POST(const char* relativePath, http_async_handler handlerFunc) {
Handle("POST", relativePath, handlerFunc);
}
void POST(const char* relativePath, http_ctx_handler handlerFunc) {
Handle("POST", relativePath, handlerFunc);
}
// PUT
void PUT(const char* relativePath, http_sync_handler handlerFunc) {
Handle("PUT", relativePath, handlerFunc);
}
void PUT(const char* relativePath, http_async_handler handlerFunc) {
Handle("PUT", relativePath, handlerFunc);
}
void PUT(const char* relativePath, http_ctx_handler handlerFunc) {
Handle("PUT", relativePath, handlerFunc);
}
// DELETE
// NOTE: Windows <winnt.h> #define DELETE as a macro, we have to replace DELETE with Delete.
void Delete(const char* relativePath, http_sync_handler handlerFunc) {
Handle("DELETE", relativePath, handlerFunc);
}
void Delete(const char* relativePath, http_async_handler handlerFunc) {
Handle("DELETE", relativePath, handlerFunc);
}
void Delete(const char* relativePath, http_ctx_handler handlerFunc) {
Handle("DELETE", relativePath, handlerFunc);
}
// PATCH
void PATCH(const char* relativePath, http_sync_handler handlerFunc) {
Handle("PATCH", relativePath, handlerFunc);
}
void PATCH(const char* relativePath, http_async_handler handlerFunc) {
Handle("PATCH", relativePath, handlerFunc);
}
void PATCH(const char* relativePath, http_ctx_handler handlerFunc) {
Handle("PATCH", relativePath, handlerFunc);
}
// Any
void Any(const char* relativePath, http_sync_handler handlerFunc) {
Handle("HEAD", relativePath, handlerFunc);
Handle("GET", relativePath, handlerFunc);
Handle("POST", relativePath, handlerFunc);
Handle("PUT", relativePath, handlerFunc);
Handle("DELETE", relativePath, handlerFunc);
Handle("PATCH", relativePath, handlerFunc);
}
void Any(const char* relativePath, http_async_handler handlerFunc) {
Handle("HEAD", relativePath, handlerFunc);
Handle("GET", relativePath, handlerFunc);
Handle("POST", relativePath, handlerFunc);
Handle("PUT", relativePath, handlerFunc);
Handle("DELETE", relativePath, handlerFunc);
Handle("PATCH", relativePath, handlerFunc);
}
void Any(const char* relativePath, http_ctx_handler handlerFunc) {
Handle("HEAD", relativePath, handlerFunc);
Handle("GET", relativePath, handlerFunc);
Handle("POST", relativePath, handlerFunc);
Handle("PUT", relativePath, handlerFunc);
Handle("DELETE", relativePath, handlerFunc);
Handle("PATCH", relativePath, handlerFunc);
}
};
}
#endif // HV_HTTP_SERVICE_H_

View File

@ -0,0 +1,56 @@
#ifndef HV_STATUS_HPP_
#define HV_STATUS_HPP_
#include <atomic>
namespace hv {
class Status {
public:
enum KStatus {
kNull = 0,
kInitializing = 1,
kInitialized = 2,
kStarting = 3,
kStarted = 4,
kRunning = 5,
kPause = 6,
kStopping = 7,
kStopped = 8,
kDestroyed = 9,
};
Status() {
status_ = kNull;
}
~Status() {
status_ = kDestroyed;
}
KStatus status() {
return status_;
}
void setStatus(KStatus status) {
status_ = status;
}
bool isRunning() {
return status_ == kRunning;
}
bool isPause() {
return status_ == kPause;
}
bool isStopped() {
return status_ == kStopped;
}
private:
std::atomic<KStatus> status_;
};
}
#endif // HV_STATUS_HPP_

View File

@ -0,0 +1,227 @@
#ifndef HV_TCP_CLIENT_HPP_
#define HV_TCP_CLIENT_HPP_
#include "hsocket.h"
#include "hssl.h"
#include "hlog.h"
#include "EventLoopThread.h"
#include "Channel.h"
namespace hv {
template<class TSocketChannel = SocketChannel>
class TcpClientTmpl {
public:
typedef std::shared_ptr<TSocketChannel> TSocketChannelPtr;
TcpClientTmpl() {
connect_timeout = HIO_DEFAULT_CONNECT_TIMEOUT;
tls = false;
tls_setting = NULL;
reconn_setting = NULL;
unpack_setting = NULL;
}
virtual ~TcpClientTmpl() {
HV_FREE(tls_setting);
HV_FREE(reconn_setting);
HV_FREE(unpack_setting);
}
const EventLoopPtr& loop() {
return loop_thread.loop();
}
//NOTE: By default, not bind local port. If necessary, you can call system api bind() after createsocket().
//@retval >=0 connfd, <0 error
int createsocket(int remote_port, const char* remote_host = "127.0.0.1") {
memset(&remote_addr, 0, sizeof(remote_addr));
int ret = sockaddr_set_ipport(&remote_addr, remote_host, remote_port);
if (ret != 0) {
return -1;
}
this->remote_host = remote_host;
this->remote_port = remote_port;
return createsocket(&remote_addr.sa);
}
int createsocket(struct sockaddr* remote_addr) {
int connfd = socket(remote_addr->sa_family, SOCK_STREAM, 0);
// SOCKADDR_PRINT(remote_addr);
if (connfd < 0) {
perror("socket");
return -2;
}
hio_t* io = hio_get(loop_thread.hloop(), connfd);
assert(io != NULL);
hio_set_peeraddr(io, remote_addr, SOCKADDR_LEN(remote_addr));
channel.reset(new TSocketChannel(io));
return connfd;
}
// closesocket thread-safe
void closesocket() {
setReconnect(NULL);
if (channel) {
channel->close(true);
}
}
int startConnect() {
assert(channel != NULL);
if (connect_timeout) {
channel->setConnectTimeout(connect_timeout);
}
if (tls) {
channel->enableSSL();
if (tls_setting) {
channel->newSslCtx(tls_setting);
}
if (!is_ipaddr(remote_host.c_str())) {
channel->setHostname(remote_host);
}
}
channel->onconnect = [this]() {
if (unpack_setting) {
channel->setUnpack(unpack_setting);
}
channel->startRead();
if (onConnection) {
onConnection(channel);
}
if (reconn_setting) {
reconn_setting_reset(reconn_setting);
}
};
channel->onread = [this](Buffer* buf) {
if (onMessage) {
onMessage(channel, buf);
}
};
channel->onwrite = [this](Buffer* buf) {
if (onWriteComplete) {
onWriteComplete(channel, buf);
}
};
channel->onclose = [this]() {
if (onConnection) {
onConnection(channel);
}
// reconnect
if (reconn_setting) {
startReconnect();
} else {
channel = NULL;
// NOTE: channel should be destroyed,
// so in this lambda function, no code should be added below.
}
};
return channel->startConnect();
}
int startReconnect() {
if (!reconn_setting) return -1;
if (!reconn_setting_can_retry(reconn_setting)) return -2;
uint32_t delay = reconn_setting_calc_delay(reconn_setting);
loop_thread.loop()->setTimeout(delay, [this](TimerID timerID){
hlogi("reconnect... cnt=%d, delay=%d", reconn_setting->cur_retry_cnt, reconn_setting->cur_delay);
if (createsocket(&remote_addr.sa) < 0) return;
startConnect();
});
return 0;
}
void start(bool wait_threads_started = true) {
loop_thread.start(wait_threads_started, std::bind(&TcpClientTmpl::startConnect, this));
}
// stop thread-safe
void stop(bool wait_threads_stopped = true) {
setReconnect(NULL);
loop_thread.stop(wait_threads_stopped);
}
bool isConnected() {
if (channel == NULL) return false;
return channel->isConnected();
}
// send thread-safe
int send(const void* data, int size) {
if (!isConnected()) return -1;
return channel->write(data, size);
}
int send(Buffer* buf) {
return send(buf->data(), buf->size());
}
int send(const std::string& str) {
return send(str.data(), str.size());
}
int withTLS(hssl_ctx_opt_t* opt = NULL) {
tls = true;
if (opt) {
if (tls_setting == NULL) {
HV_ALLOC_SIZEOF(tls_setting);
}
opt->endpoint = HSSL_CLIENT;
*tls_setting = *opt;
}
return 0;
}
void setConnectTimeout(int ms) {
connect_timeout = ms;
}
void setReconnect(reconn_setting_t* setting) {
if (setting == NULL) {
HV_FREE(reconn_setting);
return;
}
if (reconn_setting == NULL) {
HV_ALLOC_SIZEOF(reconn_setting);
}
*reconn_setting = *setting;
}
bool isReconnect() {
return reconn_setting && reconn_setting->cur_retry_cnt > 0;
}
void setUnpack(unpack_setting_t* setting) {
if (setting == NULL) {
HV_FREE(unpack_setting);
return;
}
if (unpack_setting == NULL) {
HV_ALLOC_SIZEOF(unpack_setting);
}
*unpack_setting = *setting;
}
public:
TSocketChannelPtr channel;
std::string remote_host;
int remote_port;
sockaddr_u remote_addr;
int connect_timeout;
bool tls;
hssl_ctx_opt_t* tls_setting;
reconn_setting_t* reconn_setting;
unpack_setting_t* unpack_setting;
// Callback
std::function<void(const TSocketChannelPtr&)> onConnection;
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
// NOTE: Use Channel::isWriteComplete in onWriteComplete callback to determine whether all data has been written.
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
private:
EventLoopThread loop_thread;
};
typedef TcpClientTmpl<SocketChannel> TcpClient;
}
#endif // HV_TCP_CLIENT_HPP_

View File

@ -0,0 +1,236 @@
#ifndef HV_TCP_SERVER_HPP_
#define HV_TCP_SERVER_HPP_
#include "hsocket.h"
#include "hssl.h"
#include "hlog.h"
#include "EventLoopThreadPool.h"
#include "Channel.h"
namespace hv {
template<class TSocketChannel = SocketChannel>
class TcpServerTmpl {
public:
typedef std::shared_ptr<TSocketChannel> TSocketChannelPtr;
TcpServerTmpl() {
listenfd = -1;
tls = false;
unpack_setting.mode = UNPACK_MODE_NONE;
max_connections = 0xFFFFFFFF;
load_balance = LB_RoundRobin;
}
virtual ~TcpServerTmpl() {
}
EventLoopPtr loop(int idx = -1) {
return worker_threads.loop(idx);
}
//@retval >=0 listenfd, <0 error
int createsocket(int port, const char* host = "0.0.0.0") {
listenfd = Listen(port, host);
return listenfd;
}
// closesocket thread-safe
void closesocket() {
if (listenfd >= 0) {
hio_close_async(hio_get(acceptor_thread.hloop(), listenfd));
listenfd = -1;
}
}
void setMaxConnectionNum(uint32_t num) {
max_connections = num;
}
void setLoadBalance(load_balance_e lb) {
load_balance = lb;
}
// NOTE: totalThreadNum = 1 acceptor_thread + N worker_threads (N can be 0)
void setThreadNum(int num) {
worker_threads.setThreadNum(num);
}
int startAccept() {
assert(listenfd >= 0);
hio_t* listenio = haccept(acceptor_thread.hloop(), listenfd, onAccept);
hevent_set_userdata(listenio, this);
if (tls) {
hio_enable_ssl(listenio);
}
return 0;
}
void start(bool wait_threads_started = true) {
if (worker_threads.threadNum() > 0) {
worker_threads.start(wait_threads_started);
}
acceptor_thread.start(wait_threads_started, std::bind(&TcpServerTmpl::startAccept, this));
}
// stop thread-safe
void stop(bool wait_threads_stopped = true) {
acceptor_thread.stop(wait_threads_stopped);
if (worker_threads.threadNum() > 0) {
worker_threads.stop(wait_threads_stopped);
}
}
int withTLS(hssl_ctx_opt_t* opt = NULL) {
tls = true;
if (opt) {
opt->endpoint = HSSL_SERVER;
if (hssl_ctx_init(opt) == NULL) {
fprintf(stderr, "hssl_ctx_init failed!\n");
return -1;
}
}
return 0;
}
void setUnpack(unpack_setting_t* setting) {
if (setting) {
unpack_setting = *setting;
} else {
unpack_setting.mode = UNPACK_MODE_NONE;
}
}
// channel
const TSocketChannelPtr& addChannel(hio_t* io) {
uint32_t id = hio_id(io);
auto channel = TSocketChannelPtr(new TSocketChannel(io));
std::lock_guard<std::mutex> locker(mutex_);
channels[id] = channel;
return channels[id];
}
TSocketChannelPtr getChannelById(uint32_t id) {
std::lock_guard<std::mutex> locker(mutex_);
auto iter = channels.find(id);
return iter != channels.end() ? iter->second : NULL;
}
void removeChannel(const TSocketChannelPtr& channel) {
uint32_t id = channel->id();
std::lock_guard<std::mutex> locker(mutex_);
channels.erase(id);
}
size_t connectionNum() {
std::lock_guard<std::mutex> locker(mutex_);
return channels.size();
}
int foreachChannel(std::function<void(const TSocketChannelPtr& channel)> fn) {
std::lock_guard<std::mutex> locker(mutex_);
for (auto& pair : channels) {
fn(pair.second);
}
return channels.size();
}
// broadcast thread-safe
int broadcast(const void* data, int size) {
return foreachChannel([data, size](const TSocketChannelPtr& channel) {
channel->write(data, size);
});
}
int broadcast(const std::string& str) {
return broadcast(str.data(), str.size());
}
private:
static void newConnEvent(hio_t* connio) {
TcpServerTmpl* server = (TcpServerTmpl*)hevent_userdata(connio);
if (server->connectionNum() >= server->max_connections) {
hlogw("over max_connections");
hio_close(connio);
return;
}
// NOTE: attach to worker loop
EventLoop* worker_loop = currentThreadEventLoop;
assert(worker_loop != NULL);
hio_attach(worker_loop->loop(), connio);
const TSocketChannelPtr& channel = server->addChannel(connio);
channel->status = SocketChannel::CONNECTED;
channel->onread = [server, &channel](Buffer* buf) {
if (server->onMessage) {
server->onMessage(channel, buf);
}
};
channel->onwrite = [server, &channel](Buffer* buf) {
if (server->onWriteComplete) {
server->onWriteComplete(channel, buf);
}
};
channel->onclose = [server, &channel]() {
EventLoop* worker_loop = currentThreadEventLoop;
assert(worker_loop != NULL);
--worker_loop->connectionNum;
channel->status = SocketChannel::CLOSED;
if (server->onConnection) {
server->onConnection(channel);
}
server->removeChannel(channel);
// NOTE: After removeChannel, channel may be destroyed,
// so in this lambda function, no code should be added below.
};
if (server->unpack_setting.mode != UNPACK_MODE_NONE) {
channel->setUnpack(&server->unpack_setting);
}
channel->startRead();
if (server->onConnection) {
server->onConnection(channel);
}
}
static void onAccept(hio_t* connio) {
TcpServerTmpl* server = (TcpServerTmpl*)hevent_userdata(connio);
// NOTE: detach from acceptor loop
hio_detach(connio);
EventLoopPtr worker_loop = server->worker_threads.nextLoop(server->load_balance);
if (worker_loop == NULL) {
worker_loop = server->acceptor_thread.loop();
}
++worker_loop->connectionNum;
worker_loop->runInLoop(std::bind(&TcpServerTmpl::newConnEvent, connio));
}
public:
int listenfd;
bool tls;
unpack_setting_t unpack_setting;
// Callback
std::function<void(const TSocketChannelPtr&)> onConnection;
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
// NOTE: Use Channel::isWriteComplete in onWriteComplete callback to determine whether all data has been written.
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
uint32_t max_connections;
load_balance_e load_balance;
private:
// id => TSocketChannelPtr
std::map<uint32_t, TSocketChannelPtr> channels; // GUAREDE_BY(mutex_)
std::mutex mutex_;
EventLoopThread acceptor_thread;
EventLoopThreadPool worker_threads;
};
typedef TcpServerTmpl<SocketChannel> TcpServer;
}
#endif // HV_TCP_SERVER_HPP_

View File

@ -0,0 +1,67 @@
#ifndef HV_THREAD_LOCAL_STORAGE_H_
#define HV_THREAD_LOCAL_STORAGE_H_
#include "hexport.h"
#include "hplatform.h"
#ifdef OS_WIN
#define hthread_key_t DWORD
#define INVALID_HTHREAD_KEY 0xFFFFFFFF
#define hthread_key_create(pkey) *pkey = TlsAlloc()
#define hthread_key_delete TlsFree
#define hthread_get_value TlsGetValue
#define hthread_set_value TlsSetValue
#else
#define hthread_key_t pthread_key_t
#define INVALID_HTHREAD_KEY 0xFFFFFFFF
#define hthread_key_create(pkey) pthread_key_create(pkey, NULL)
#define hthread_key_delete pthread_key_delete
#define hthread_get_value pthread_getspecific
#define hthread_set_value pthread_setspecific
#endif
#ifdef __cplusplus
namespace hv {
class HV_EXPORT ThreadLocalStorage {
public:
enum {
THREAD_NAME = 0,
EVENT_LOOP = 1,
MAX_NUM = 16,
};
ThreadLocalStorage() {
hthread_key_create(&key);
}
~ThreadLocalStorage() {
hthread_key_delete(key);
}
void set(void* val) {
hthread_set_value(key, val);
}
void* get() {
return hthread_get_value(key);
}
static void set(int idx, void* val);
static void* get(int idx);
static void setThreadName(const char* name);
static const char* threadName();
private:
hthread_key_t key;
static ThreadLocalStorage tls[MAX_NUM];
};
}
#endif
#endif // HV_THREAD_LOCAL_STORAGE_H_

View File

@ -0,0 +1,117 @@
#ifndef HV_UDP_CLIENT_HPP_
#define HV_UDP_CLIENT_HPP_
#include "hsocket.h"
#include "EventLoopThread.h"
#include "Channel.h"
namespace hv {
template<class TSocketChannel = SocketChannel>
class UdpClientTmpl {
public:
typedef std::shared_ptr<TSocketChannel> TSocketChannelPtr;
UdpClientTmpl() {
#if WITH_KCP
enable_kcp = false;
#endif
}
virtual ~UdpClientTmpl() {
}
const EventLoopPtr& loop() {
return loop_thread.loop();
}
//NOTE: By default, not bind local port. If necessary, you can call system api bind() after createsocket().
//@retval >=0 sockfd, <0 error
int createsocket(int remote_port, const char* remote_host = "127.0.0.1") {
hio_t* io = hloop_create_udp_client(loop_thread.hloop(), remote_host, remote_port);
if (io == NULL) return -1;
channel.reset(new TSocketChannel(io));
return channel->fd();
}
// closesocket thread-safe
void closesocket() {
if (channel) {
channel->close(true);
}
}
int startRecv() {
assert(channel != NULL);
channel->onread = [this](Buffer* buf) {
if (onMessage) {
onMessage(channel, buf);
}
};
channel->onwrite = [this](Buffer* buf) {
if (onWriteComplete) {
onWriteComplete(channel, buf);
}
};
#if WITH_KCP
if (enable_kcp) {
hio_set_kcp(channel->io(), &kcp_setting);
}
#endif
return channel->startRead();
}
void start(bool wait_threads_started = true) {
loop_thread.start(wait_threads_started, std::bind(&UdpClientTmpl::startRecv, this));
}
// stop thread-safe
void stop(bool wait_threads_stopped = true) {
loop_thread.stop(wait_threads_stopped);
}
// sendto thread-safe
int sendto(const void* data, int size, struct sockaddr* peeraddr = NULL) {
if (channel == NULL) return -1;
std::lock_guard<std::mutex> locker(sendto_mutex);
if (peeraddr) hio_set_peeraddr(channel->io(), peeraddr, SOCKADDR_LEN(peeraddr));
return channel->write(data, size);
}
int sendto(Buffer* buf, struct sockaddr* peeraddr = NULL) {
return sendto(buf->data(), buf->size(), peeraddr);
}
int sendto(const std::string& str, struct sockaddr* peeraddr = NULL) {
return sendto(str.data(), str.size(), peeraddr);
}
#if WITH_KCP
void setKcp(kcp_setting_t* setting) {
if (setting) {
enable_kcp = true;
kcp_setting = *setting;
} else {
enable_kcp = false;
}
}
#endif
public:
TSocketChannelPtr channel;
#if WITH_KCP
bool enable_kcp;
kcp_setting_t kcp_setting;
#endif
// Callback
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
// NOTE: Use Channel::isWriteComplete in onWriteComplete callback to determine whether all data has been written.
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
private:
std::mutex sendto_mutex;
EventLoopThread loop_thread;
};
typedef UdpClientTmpl<SocketChannel> UdpClient;
}
#endif // HV_UDP_CLIENT_HPP_

View File

@ -0,0 +1,105 @@
#ifndef HV_UDP_SERVER_HPP_
#define HV_UDP_SERVER_HPP_
#include "hsocket.h"
#include "EventLoopThreadPool.h"
#include "Channel.h"
namespace hv {
template<class TSocketChannel = SocketChannel>
class UdpServerTmpl {
public:
typedef std::shared_ptr<TSocketChannel> TSocketChannelPtr;
UdpServerTmpl() {
#if WITH_KCP
enable_kcp = false;
#endif
}
virtual ~UdpServerTmpl() {
}
const EventLoopPtr& loop() {
return loop_thread.loop();
}
//@retval >=0 bindfd, <0 error
int createsocket(int port, const char* host = "0.0.0.0") {
hio_t* io = hloop_create_udp_server(loop_thread.hloop(), host, port);
if (io == NULL) return -1;
channel.reset(new TSocketChannel(io));
return channel->fd();
}
// closesocket thread-safe
void closesocket() {
if (channel) {
channel->close(true);
}
}
int startRecv() {
assert(channel != NULL);
channel->onread = [this](Buffer* buf) {
if (onMessage) {
onMessage(channel, buf);
}
};
channel->onwrite = [this](Buffer* buf) {
if (onWriteComplete) {
onWriteComplete(channel, buf);
}
};
#if WITH_KCP
if (enable_kcp) {
hio_set_kcp(channel->io(), &kcp_setting);
}
#endif
return channel->startRead();
}
void start(bool wait_threads_started = true) {
loop_thread.start(wait_threads_started, std::bind(&UdpServerTmpl::startRecv, this));
}
// stop thread-safe
void stop(bool wait_threads_stopped = true) {
loop_thread.stop(wait_threads_stopped);
}
// sendto thread-safe
int sendto(const void* data, int size, struct sockaddr* peeraddr = NULL) {
if (channel == NULL) return -1;
std::lock_guard<std::mutex> locker(sendto_mutex);
if (peeraddr) hio_set_peeraddr(channel->io(), peeraddr, SOCKADDR_LEN(peeraddr));
return channel->write(data, size);
}
int sendto(Buffer* buf, struct sockaddr* peeraddr = NULL) {
return sendto(buf->data(), buf->size(), peeraddr);
}
int sendto(const std::string& str, struct sockaddr* peeraddr = NULL) {
return sendto(str.data(), str.size(), peeraddr);
}
public:
TSocketChannelPtr channel;
#if WITH_KCP
bool enable_kcp;
kcp_setting_t kcp_setting;
#endif
// Callback
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
// NOTE: Use Channel::isWriteComplete in onWriteComplete callback to determine whether all data has been written.
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
private:
std::mutex sendto_mutex;
EventLoopThread loop_thread;
};
typedef UdpServerTmpl<SocketChannel> UdpServer;
}
#endif // HV_UDP_SERVER_HPP_

View File

@ -0,0 +1,111 @@
#ifndef HV_WEBSOCKET_CHANNEL_H_
#define HV_WEBSOCKET_CHANNEL_H_
#include <mutex>
#include "Channel.h"
#include "wsdef.h"
#include "hmath.h"
namespace hv {
class WebSocketChannel : public SocketChannel {
public:
ws_session_type type;
WebSocketChannel(hio_t* io, ws_session_type type = WS_CLIENT)
: SocketChannel(io)
, type(type)
{}
~WebSocketChannel() {}
// isConnected, send, close
int send(const std::string& msg, enum ws_opcode opcode = WS_OPCODE_TEXT, bool fin = true) {
return send(msg.c_str(), msg.size(), opcode, fin);
}
int send(const char* buf, int len, enum ws_opcode opcode = WS_OPCODE_BINARY, bool fin = true) {
int fragment = 0xFFFF; // 65535
if (len > fragment) {
return send(buf, len, fragment, opcode);
}
std::lock_guard<std::mutex> locker(mutex_);
return sendFrame(buf, len, opcode, fin);
}
// websocket fragment
// lock ->
// send(p, fragment, opcode, false) ->
// send(p, fragment, WS_OPCODE_CONTINUE, false) ->
// ... ->
// send(p, remain, WS_OPCODE_CONTINUE, true)
// unlock
int send(const char* buf, int len, int fragment, enum ws_opcode opcode = WS_OPCODE_BINARY) {
std::lock_guard<std::mutex> locker(mutex_);
if (len <= fragment) {
return sendFrame(buf, len, opcode, true);
}
// first fragment
int nsend = sendFrame(buf, fragment, opcode, false);
if (nsend < 0) return nsend;
const char* p = buf + fragment;
int remain = len - fragment;
while (remain > fragment) {
nsend = sendFrame(p, fragment, WS_OPCODE_CONTINUE, false);
if (nsend < 0) return nsend;
p += fragment;
remain -= fragment;
}
// last fragment
nsend = sendFrame(p, remain, WS_OPCODE_CONTINUE, true);
if (nsend < 0) return nsend;
return len;
}
int sendPing() {
std::lock_guard<std::mutex> locker(mutex_);
if (type == WS_CLIENT) {
return write(WS_CLIENT_PING_FRAME, WS_CLIENT_MIN_FRAME_SIZE);
}
return write(WS_SERVER_PING_FRAME, WS_SERVER_MIN_FRAME_SIZE);
}
int sendPong() {
std::lock_guard<std::mutex> locker(mutex_);
if (type == WS_CLIENT) {
return write(WS_CLIENT_PONG_FRAME, WS_CLIENT_MIN_FRAME_SIZE);
}
return write(WS_SERVER_PONG_FRAME, WS_SERVER_MIN_FRAME_SIZE);
}
protected:
int sendFrame(const char* buf, int len, enum ws_opcode opcode = WS_OPCODE_BINARY, bool fin = true) {
bool has_mask = false;
char mask[4] = {0};
if (type == WS_CLIENT) {
*(int*)mask = rand();
has_mask = true;
}
int frame_size = ws_calc_frame_size(len, has_mask);
if (sendbuf_.len < frame_size) {
sendbuf_.resize(ceil2e(frame_size));
}
ws_build_frame(sendbuf_.base, buf, len, mask, has_mask, opcode, fin);
return write(sendbuf_.base, frame_size);
}
private:
Buffer sendbuf_;
std::mutex mutex_;
};
}
typedef std::shared_ptr<hv::WebSocketChannel> WebSocketChannelPtr;
#endif // HV_WEBSOCKET_CHANNEL_H_

View File

@ -0,0 +1,59 @@
#ifndef HV_WEBSOCKET_CLIENT_H_
#define HV_WEBSOCKET_CLIENT_H_
/*
* @demo examples/websocket_client_test.cpp
*/
#include "hexport.h"
#include "TcpClient.h"
#include "WebSocketChannel.h"
#include "HttpParser.h"
#include "WebSocketParser.h"
namespace hv {
class HV_EXPORT WebSocketClient : public TcpClientTmpl<WebSocketChannel> {
public:
std::string url;
std::function<void()> onopen;
std::function<void()> onclose;
std::function<void(const std::string& msg)> onmessage;
WebSocketClient();
~WebSocketClient();
// url = ws://ip:port/path
// url = wss://ip:port/path
int open(const char* url, const http_headers& headers = DefaultHeaders);
int close();
int send(const std::string& msg);
int send(const char* buf, int len, enum ws_opcode opcode = WS_OPCODE_BINARY);
// setConnectTimeout / setPingInterval / setReconnect
void setPingInterval(int ms) {
ping_interval = ms;
}
private:
enum State {
CONNECTING,
CONNECTED,
WS_UPGRADING,
WS_OPENED,
WS_CLOSED,
} state;
HttpParserPtr http_parser_;
HttpRequestPtr http_req_;
HttpResponsePtr http_resp_;
WebSocketParserPtr ws_parser_;
// ping/pong
int ping_interval;
int ping_cnt;
};
}
#endif // HV_WEBSOCKET_CLIENT_H_

View File

@ -0,0 +1,35 @@
#ifndef HV_WEBSOCKET_PARSER_H_
#define HV_WEBSOCKET_PARSER_H_
#include "hexport.h"
#include <string>
#include <memory>
#include <functional>
enum websocket_parser_state {
WS_FRAME_BEGIN,
WS_FRAME_HEADER,
WS_FRAME_BODY,
WS_FRAME_END,
WS_FRAME_FIN,
};
struct websocket_parser;
class HV_EXPORT WebSocketParser {
public:
websocket_parser* parser;
websocket_parser_state state;
int opcode;
std::string message;
std::function<void(int opcode, const std::string& msg)> onMessage;
WebSocketParser();
~WebSocketParser();
int FeedRecvData(const char* data, size_t len);
};
typedef std::shared_ptr<WebSocketParser> WebSocketParserPtr;
#endif // HV_WEBSOCKET_PARSER_H_

View File

@ -0,0 +1,37 @@
#ifndef HV_WEBSOCKET_SERVER_H_
#define HV_WEBSOCKET_SERVER_H_
/*
* @demo examples/websocket_server_test.cpp
*/
#include "HttpServer.h"
#include "WebSocketChannel.h"
#define websocket_server_t http_server_t
#define websocket_server_run http_server_run
#define websocket_server_stop http_server_stop
namespace hv {
struct WebSocketService {
std::function<void(const WebSocketChannelPtr&, const std::string&)> onopen;
std::function<void(const WebSocketChannelPtr&, const std::string&)> onmessage;
std::function<void(const WebSocketChannelPtr&)> onclose;
int ping_interval;
WebSocketService() {
ping_interval = 10000; // ms
}
};
class WebSocketServer : public HttpServer {
public:
void registerWebSocketService(WebSocketService* service) {
this->ws = service;
}
};
}
#endif // HV_WEBSOCKET_SERVER_H_

View File

@ -0,0 +1,192 @@
#ifndef HV_AXIOS_H_
#include "json.hpp"
#include "requests.h"
/*
* Inspired by js axios
*
* @code
#include "axios.h"
int main() {
const char* strReq = R"(
{
"method": "POST",
"url": "http://127.0.0.1:8080/echo",
"timeout": 10,
"params": {
"page_no": "1",
"page_size": "10"
},
"headers": {
"Content-Type": "application/json"
},
"body": {
"app_id": "123456",
"app_secret": "abcdefg"
}
}
)";
// sync
auto resp = axios::axios(strReq);
if (resp == NULL) {
printf("request failed!\n");
} else {
printf("%s\n", resp->body.c_str());
}
// async
int finished = 0;
axios::axios(strReq, [&finished](const HttpResponsePtr& resp) {
if (resp == NULL) {
printf("request failed!\n");
} else {
printf("%s\n", resp->body.c_str());
}
finished = 1;
});
// wait async finished
while (!finished) hv_sleep(1);
return 0;
}
**/
using nlohmann::json;
using requests::Request;
using requests::Response;
using requests::ResponseCallback;
namespace axios {
HV_INLINE Request newRequestFromJson(const json& jreq) {
Request req(new HttpRequest);
// url
if (jreq.contains("url")) {
req->url = jreq["url"];
}
// params
if (jreq.contains("params")) {
req->query_params = jreq["params"].get<hv::QueryParams>();
}
// headers
if (jreq.contains("headers")) {
req->headers = jreq["headers"].get<http_headers>();
}
// body/data
const char* body_field = nullptr;
if (jreq.contains("body")) {
body_field = "body";
} else if (jreq.contains("data")) {
body_field = "data";
}
if (body_field) {
const json& jbody = jreq[body_field];
if (jbody.is_object() || jbody.is_array()) {
req->json = jbody;
} else if (jbody.is_string()) {
req->body = jbody;
}
}
// method
if (jreq.contains("method")) {
std::string method = jreq["method"];
req->method = http_method_enum(method.c_str());
} else if (body_field) {
req->method = HTTP_POST;
} else {
req->method = HTTP_GET;
}
// timeout
if (jreq.contains("timeout")) {
req->timeout = jreq["timeout"];
}
return req;
}
HV_INLINE Request newRequestFromJsonString(const char* req_str) {
return newRequestFromJson(json::parse(req_str));
}
// sync
HV_INLINE Response axios(const json& jreq, http_method method = HTTP_GET, const char* url = nullptr) {
auto req = newRequestFromJson(jreq);
if (method != HTTP_GET) {
req->method = method;
}
if (url) {
req->url = url;
}
return req ? requests::request(req) : nullptr;
}
HV_INLINE Response axios(const char* req_str, http_method method = HTTP_GET, const char* url = nullptr) {
return req_str ? axios(json::parse(req_str), method, url)
: requests::request(method, url);
}
HV_INLINE Response head(const char* url, const json& jreq) {
return axios(jreq, HTTP_HEAD, url);
}
HV_INLINE Response head(const char* url, const char* req_str = nullptr) {
return axios(req_str, HTTP_HEAD, url);
}
HV_INLINE Response get(const char* url, const json& jreq) {
return axios(jreq, HTTP_GET, url);
}
HV_INLINE Response get(const char* url, const char* req_str = nullptr) {
return axios(req_str, HTTP_GET, url);
}
HV_INLINE Response post(const char* url, const json& jreq) {
return axios(jreq, HTTP_POST, url);
}
HV_INLINE Response post(const char* url, const char* req_str = nullptr) {
return axios(req_str, HTTP_POST, url);
}
HV_INLINE Response put(const char* url, const json& jreq) {
return axios(jreq, HTTP_PUT, url);
}
HV_INLINE Response put(const char* url, const char* req_str = nullptr) {
return axios(req_str, HTTP_PUT, url);
}
HV_INLINE Response patch(const char* url, const json& jreq) {
return axios(jreq, HTTP_PATCH, url);
}
HV_INLINE Response patch(const char* url, const char* req_str = nullptr) {
return axios(req_str, HTTP_PATCH, url);
}
HV_INLINE Response Delete(const char* url, const json& jreq) {
return axios(jreq, HTTP_DELETE, url);
}
HV_INLINE Response Delete(const char* url, const char* req_str = nullptr) {
return axios(req_str, HTTP_DELETE, url);
}
// async
HV_INLINE int axios(const json& jreq, ResponseCallback resp_cb) {
auto req = newRequestFromJson(jreq);
return req ? requests::async(req, std::move(resp_cb)) : -1;
}
HV_INLINE int axios(const char* req_str, ResponseCallback resp_cb) {
return axios(json::parse(req_str), std::move(resp_cb));
}
}
#endif // HV_AXIOS_H_

View File

@ -0,0 +1,46 @@
#ifndef HV_BASE64_H_
#define HV_BASE64_H_
#include "hexport.h"
#define BASE64_ENCODE_OUT_SIZE(s) (((s) + 2) / 3 * 4)
#define BASE64_DECODE_OUT_SIZE(s) (((s)) / 4 * 3)
BEGIN_EXTERN_C
// @return encoded size
HV_EXPORT int hv_base64_encode(const unsigned char *in, unsigned int inlen, char *out);
// @return decoded size
HV_EXPORT int hv_base64_decode(const char *in, unsigned int inlen, unsigned char *out);
END_EXTERN_C
#ifdef __cplusplus
#include <string.h>
#include <string>
namespace hv {
HV_INLINE std::string Base64Encode(const unsigned char* data, unsigned int len) {
int encoded_size = BASE64_ENCODE_OUT_SIZE(len);
std::string encoded_str(encoded_size + 1, 0);
encoded_size = hv_base64_encode(data, len, (char*)encoded_str.data());
encoded_str.resize(encoded_size);
return encoded_str;
}
HV_INLINE std::string Base64Decode(const char* str, unsigned int len = 0) {
if (len == 0) len = strlen(str);
int decoded_size = BASE64_DECODE_OUT_SIZE(len);
std::string decoded_buf(decoded_size + 1, 0);
decoded_size = hv_base64_decode(str, len, (unsigned char*)decoded_buf.data());
decoded_buf.resize(decoded_size);
return decoded_buf;
}
}
#endif
#endif // HV_BASE64_H_

View File

@ -0,0 +1,105 @@
#ifndef HV_DNS_H_
#define HV_DNS_H_
#include "hexport.h"
#include "hplatform.h"
#define DNS_PORT 53
#define DNS_QUERY 0
#define DNS_RESPONSE 1
#define DNS_TYPE_A 1 // ipv4
#define DNS_TYPE_NS 2
#define DNS_TYPE_CNAME 5
#define DNS_TYPE_SOA 6
#define DNS_TYPE_WKS 11
#define DNS_TYPE_PTR 12
#define DNS_TYPE_HINFO 13
#define DNS_TYPE_MX 15
#define DNS_TYPE_AAAA 28 // ipv6
#define DNS_TYPE_AXFR 252
#define DNS_TYPE_ANY 255
#define DNS_CLASS_IN 1
#define DNS_NAME_MAXLEN 256
// sizeof(dnshdr_t) = 12
typedef struct dnshdr_s {
uint16_t transaction_id;
// flags
#if BYTE_ORDER == LITTLE_ENDIAN
uint8_t rd:1;
uint8_t tc:1;
uint8_t aa:1;
uint8_t opcode:4;
uint8_t qr:1;
uint8_t rcode:4;
uint8_t cd:1;
uint8_t ad:1;
uint8_t res:1;
uint8_t ra:1;
#elif BYTE_ORDER == BIG_ENDIAN
uint8_t qr:1; // DNS_QUERY or DNS_RESPONSE
uint8_t opcode:4;
uint8_t aa:1; // authoritative
uint8_t tc:1; // truncated
uint8_t rd:1; // recursion desired
uint8_t ra:1; // recursion available
uint8_t res:1; // reserved
uint8_t ad:1; // authenticated data
uint8_t cd:1; // checking disable
uint8_t rcode:4;
#else
#error "BYTE_ORDER undefined!"
#endif
uint16_t nquestion;
uint16_t nanswer;
uint16_t nauthority;
uint16_t naddtional;
} dnshdr_t;
typedef struct dns_rr_s {
char name[DNS_NAME_MAXLEN]; // original domain, such as www.example.com
uint16_t rtype;
uint16_t rclass;
uint32_t ttl;
uint16_t datalen;
char* data;
} dns_rr_t;
typedef struct dns_s {
dnshdr_t hdr;
dns_rr_t* questions;
dns_rr_t* answers;
dns_rr_t* authorities;
dns_rr_t* addtionals;
} dns_t;
BEGIN_EXTERN_C
// www.example.com => 3www7example3com
HV_EXPORT int dns_name_encode(const char* domain, char* buf);
// 3www7example3com => www.example.com
HV_EXPORT int dns_name_decode(const char* buf, char* domain);
HV_EXPORT int dns_rr_pack(dns_rr_t* rr, char* buf, int len);
HV_EXPORT int dns_rr_unpack(char* buf, int len, dns_rr_t* rr, int is_question);
HV_EXPORT int dns_pack(dns_t* dns, char* buf, int len);
HV_EXPORT int dns_unpack(char* buf, int len, dns_t* dns);
// NOTE: free dns->rrs
HV_EXPORT void dns_free(dns_t* dns);
// dns_pack -> sendto -> recvfrom -> dns_unpack
HV_EXPORT int dns_query(dns_t* query, dns_t* response, const char* nameserver DEFAULT("127.0.1.1"));
// domain -> dns_t query; -> dns_query -> dns_t response; -> addrs
HV_EXPORT int nslookup(const char* domain, uint32_t* addrs, int naddr, const char* nameserver DEFAULT("127.0.1.1"));
END_EXTERN_C
#endif // HV_DNS_H_

View File

@ -0,0 +1,96 @@
#ifndef HV_FTP_H_
#define HV_FTP_H_
#include "hexport.h"
#define FTP_COMMAND_PORT 21
#define FTP_DATA_PORT 20
// ftp_command
// X(name)
#define FTP_COMMAND_MAP(X) \
X(HELP) \
X(USER) \
X(PASS) \
X(PWD) \
X(CWD) \
X(CDUP) \
X(MKD) \
X(RMD) \
X(STAT) \
X(SIZE) \
X(DELE) \
X(RNFR) \
X(RNTO) \
X(PORT) \
X(PASV) \
X(LIST) \
X(NLST) \
X(APPE) \
X(RETR) \
X(STOR) \
X(QUIT) \
enum ftp_command {
#define X(name) FTP_##name,
FTP_COMMAND_MAP(X)
#undef X
};
// ftp_status
// XXX(code, name, string)
#define FTP_STATUS_MAP(XXX) \
XXX(220, READY, Ready) \
XXX(221, BYE, Bye) \
XXX(226, TRANSFER_COMPLETE, Transfer complete) \
XXX(227, PASV, Entering Passive Mode) \
XXX(331, PASS, Password required) \
XXX(230, LOGIN_OK, Login OK) \
XXX(250, OK, OK) \
XXX(500, BAD_SYNTAX, Bad syntax) \
XXX(530, NOT_LOGIN, Not login) \
enum ftp_status {
#define XXX(code, name, string) FTP_STATUS_##name = code,
FTP_STATUS_MAP(XXX)
#undef XXX
};
// more friendly macros
#define FTP_MKDIR FTP_MKD
#define FTP_RMDIR FTP_RMD
#define FTP_APPEND FTP_APPE
#define FTP_REMOVE FTP_DELE
#define FTP_DOWNLOAD FTP_RETR
#define FTP_UPLOAD FTP_STOR
#define FTP_RECV_BUFSIZE 8192
typedef struct ftp_handle_s {
int sockfd;
char recvbuf[FTP_RECV_BUFSIZE];
void* userdata;
} ftp_handle_t;
BEGIN_EXTERN_C
HV_EXPORT const char* ftp_command_str(enum ftp_command cmd);
HV_EXPORT const char* ftp_status_str(enum ftp_status status);
HV_EXPORT int ftp_connect(ftp_handle_t* hftp, const char* host, int port);
HV_EXPORT int ftp_login(ftp_handle_t* hftp, const char* username, const char* password);
HV_EXPORT int ftp_quit(ftp_handle_t* hftp);
HV_EXPORT int ftp_exec(ftp_handle_t* hftp, const char* cmd, const char* param);
// local => remote
HV_EXPORT int ftp_upload(ftp_handle_t* hftp, const char* local_filepath, const char* remote_filepath);
// remote => local
HV_EXPORT int ftp_download(ftp_handle_t* hftp, const char* remote_filepath, const char* local_filepath);
typedef int (*ftp_download_cb)(ftp_handle_t* hftp, char* buf, int len);
HV_EXPORT int ftp_download_with_cb(ftp_handle_t* hftp, const char* filepath, ftp_download_cb cb);
END_EXTERN_C
#endif // HV_FTP_H_

View File

@ -0,0 +1,49 @@
#ifndef HV_ASYNC_H_
#define HV_ASYNC_H_
#include "hexport.h"
#include "hthreadpool.h"
#include "singleton.h"
namespace hv {
class HV_EXPORT GlobalThreadPool : public HThreadPool {
SINGLETON_DECL(GlobalThreadPool)
protected:
GlobalThreadPool() : HThreadPool() {}
~GlobalThreadPool() {}
};
/*
* return a future, calling future.get() will wait task done and return RetType.
* async(fn, args...)
* async(std::bind(&Class::mem_fn, &obj))
* async(std::mem_fn(&Class::mem_fn, &obj))
*
*/
template<class Fn, class... Args>
auto async(Fn&& fn, Args&&... args) -> std::future<decltype(fn(args...))> {
return GlobalThreadPool::instance()->commit(std::forward<Fn>(fn), std::forward<Args>(args)...);
}
class async {
public:
static void startup(int min_threads = DEFAULT_THREAD_POOL_MIN_THREAD_NUM,
int max_threads = DEFAULT_THREAD_POOL_MAX_THREAD_NUM,
int max_idle_ms = DEFAULT_THREAD_POOL_MAX_IDLE_TIME) {
GlobalThreadPool* gtp = GlobalThreadPool::instance();
if (gtp->isStarted()) return;
gtp->setMinThreadNum(min_threads);
gtp->setMaxThreadNum(max_threads);
gtp->setMaxIdleTime(max_idle_ms);
gtp->start();
}
static void cleanup() {
GlobalThreadPool::exitInstance();
}
};
} // end namespace hv
#endif // HV_ASYNC_H_

View File

@ -0,0 +1,124 @@
#ifndef HV_ATOMIC_H_
#define HV_ATOMIC_H_
#ifdef __cplusplus
// c++11
#include <atomic>
using std::atomic_flag;
using std::atomic_long;
#define ATOMIC_FLAG_TEST_AND_SET(p) ((p)->test_and_set())
#define ATOMIC_FLAG_CLEAR(p) ((p)->clear())
#else
#include "hplatform.h" // for HAVE_STDATOMIC_H
#if HAVE_STDATOMIC_H
// c11
#include <stdatomic.h>
#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set
#define ATOMIC_FLAG_CLEAR atomic_flag_clear
#define ATOMIC_ADD atomic_fetch_add
#define ATOMIC_SUB atomic_fetch_sub
#define ATOMIC_INC(p) ATOMIC_ADD(p, 1)
#define ATOMIC_DEC(p) ATOMIC_SUB(p, 1)
#else
typedef volatile bool atomic_bool;
typedef volatile char atomic_char;
typedef volatile unsigned char atomic_uchar;
typedef volatile short atomic_short;
typedef volatile unsigned short atomic_ushort;
typedef volatile int atomic_int;
typedef volatile unsigned int atomic_uint;
typedef volatile long atomic_long;
typedef volatile unsigned long atomic_ulong;
typedef volatile long long atomic_llong;
typedef volatile unsigned long long atomic_ullong;
typedef volatile size_t atomic_size_t;
typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
#ifdef _WIN32
#define ATOMIC_ADD InterlockedAdd
#define ATOMIC_SUB(p, n) InterlockedAdd(p, -n)
#define ATOMIC_INC InterlockedIncrement
#define ATOMIC_DEC InterlockedDecrement
#elif defined(__GNUC__)
#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set
static inline bool atomic_flag_test_and_set(atomic_flag* p) {
return !__sync_bool_compare_and_swap(&p->_Value, 0, 1);
}
#define ATOMIC_ADD __sync_fetch_and_add
#define ATOMIC_SUB __sync_fetch_and_sub
#define ATOMIC_INC(p) ATOMIC_ADD(p, 1)
#define ATOMIC_DEC(p) ATOMIC_SUB(p, 1)
#endif
#endif // HAVE_STDATOMIC_H
#endif // __cplusplus
#ifndef ATOMIC_FLAG_INIT
#define ATOMIC_FLAG_INIT { 0 }
#endif
#ifndef ATOMIC_VAR_INIT
#define ATOMIC_VAR_INIT(value) (value)
#endif
#ifndef ATOMIC_FLAG_TEST_AND_SET
#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set
static inline bool atomic_flag_test_and_set(atomic_flag* p) {
bool ret = p->_Value;
p->_Value = 1;
return ret;
}
#endif
#ifndef ATOMIC_FLAG_CLEAR
#define ATOMIC_FLAG_CLEAR atomic_flag_clear
static inline void atomic_flag_clear(atomic_flag* p) {
p->_Value = 0;
}
#endif
#ifndef ATOMIC_ADD
#define ATOMIC_ADD(p, n) (*(p) += (n))
#endif
#ifndef ATOMIC_SUB
#define ATOMIC_SUB(p, n) (*(p) -= (n))
#endif
#ifndef ATOMIC_INC
#define ATOMIC_INC(p) ((*(p))++)
#endif
#ifndef ATOMIC_DEC
#define ATOMIC_DEC(p) ((*(p))--)
#endif
typedef atomic_flag hatomic_flag_t;
#define HATOMIC_FLAG_INIT ATOMIC_FLAG_INIT
#define hatomic_flag_test_and_set ATOMIC_FLAG_TEST_AND_SET
#define hatomic_flag_clear ATOMIC_FLAG_CLEAR
typedef atomic_long hatomic_t;
#define HATOMIC_VAR_INIT ATOMIC_VAR_INIT
#define hatomic_add ATOMIC_ADD
#define hatomic_sub ATOMIC_SUB
#define hatomic_inc ATOMIC_INC
#define hatomic_dec ATOMIC_DEC
#endif // HV_ATOMIC_H_

View File

@ -0,0 +1,143 @@
#ifndef HV_BASE_H_
#define HV_BASE_H_
#include "hexport.h"
#include "hplatform.h" // for bool
#include "hdef.h" // for printd
BEGIN_EXTERN_C
//--------------------alloc/free---------------------------
HV_EXPORT void* hv_malloc(size_t size);
HV_EXPORT void* hv_realloc(void* oldptr, size_t newsize, size_t oldsize);
HV_EXPORT void* hv_calloc(size_t nmemb, size_t size);
HV_EXPORT void* hv_zalloc(size_t size);
HV_EXPORT void hv_free(void* ptr);
#define HV_ALLOC(ptr, size)\
do {\
*(void**)&(ptr) = hv_zalloc(size);\
printd("alloc(%p, size=%llu)\tat [%s:%d:%s]\n", ptr, (unsigned long long)size, __FILE__, __LINE__, __FUNCTION__);\
} while(0)
#define HV_ALLOC_SIZEOF(ptr) HV_ALLOC(ptr, sizeof(*(ptr)))
#define HV_FREE(ptr)\
do {\
if (ptr) {\
hv_free(ptr);\
printd("free( %p )\tat [%s:%d:%s]\n", ptr, __FILE__, __LINE__, __FUNCTION__);\
ptr = NULL;\
}\
} while(0)
#define STACK_OR_HEAP_ALLOC(ptr, size, stack_size)\
unsigned char _stackbuf_[stack_size] = { 0 };\
if ((size) > (stack_size)) {\
HV_ALLOC(ptr, size);\
} else {\
*(unsigned char**)&(ptr) = _stackbuf_;\
}
#define STACK_OR_HEAP_FREE(ptr)\
if ((unsigned char*)(ptr) != _stackbuf_) {\
HV_FREE(ptr);\
}
#define HV_DEFAULT_STACKBUF_SIZE 1024
#define HV_STACK_ALLOC(ptr, size) STACK_OR_HEAP_ALLOC(ptr, size, HV_DEFAULT_STACKBUF_SIZE)
#define HV_STACK_FREE(ptr) STACK_OR_HEAP_FREE(ptr)
HV_EXPORT long hv_alloc_cnt();
HV_EXPORT long hv_free_cnt();
HV_INLINE void hv_memcheck() {
printf("Memcheck => alloc:%ld free:%ld\n", hv_alloc_cnt(), hv_free_cnt());
}
#define HV_MEMCHECK atexit(hv_memcheck);
//--------------------string-------------------------------
HV_EXPORT char* hv_strupper(char* str);
HV_EXPORT char* hv_strlower(char* str);
HV_EXPORT char* hv_strreverse(char* str);
HV_EXPORT bool hv_strstartswith(const char* str, const char* start);
HV_EXPORT bool hv_strendswith(const char* str, const char* end);
HV_EXPORT bool hv_strcontains(const char* str, const char* sub);
// strncpy n = sizeof(dest_buf)-1
// hv_strncpy n = sizeof(dest_buf)
HV_EXPORT char* hv_strncpy(char* dest, const char* src, size_t n);
// strncat n = sizeof(dest_buf)-1-strlen(dest)
// hv_strncpy n = sizeof(dest_buf)
HV_EXPORT char* hv_strncat(char* dest, const char* src, size_t n);
#if !HAVE_STRLCPY
#define strlcpy hv_strncpy
#endif
#if !HAVE_STRLCAT
#define strlcat hv_strncat
#endif
HV_EXPORT char* hv_strnchr(const char* s, char c, size_t n);
#define hv_strrchr_dot(str) strrchr(str, '.')
HV_EXPORT char* hv_strrchr_dir(const char* filepath);
// basename
HV_EXPORT const char* hv_basename(const char* filepath);
HV_EXPORT const char* hv_suffixname(const char* filename);
// mkdir -p
HV_EXPORT int hv_mkdir_p(const char* dir);
// rmdir -p
HV_EXPORT int hv_rmdir_p(const char* dir);
// path
HV_EXPORT bool hv_exists(const char* path);
HV_EXPORT bool hv_isdir(const char* path);
HV_EXPORT bool hv_isfile(const char* path);
HV_EXPORT bool hv_islink(const char* path);
HV_EXPORT size_t hv_filesize(const char* filepath);
HV_EXPORT char* get_executable_path(char* buf, int size);
HV_EXPORT char* get_executable_dir(char* buf, int size);
HV_EXPORT char* get_executable_file(char* buf, int size);
HV_EXPORT char* get_run_dir(char* buf, int size);
// random
HV_EXPORT int hv_rand(int min, int max);
HV_EXPORT char* hv_random_string(char *buf, int len);
// 1 y on yes true enable => true
HV_EXPORT bool hv_getboolean(const char* str);
// 1T2G3M4K5B => ?B
HV_EXPORT size_t hv_parse_size(const char* str);
// 1w2d3h4m5s => ?s
HV_EXPORT time_t hv_parse_time(const char* str);
// scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
typedef enum {
HV_URL_SCHEME,
HV_URL_USERNAME,
HV_URL_PASSWORD,
HV_URL_HOST,
HV_URL_PORT,
HV_URL_PATH,
HV_URL_QUERY,
HV_URL_FRAGMENT,
HV_URL_FIELD_NUM,
} hurl_field_e;
typedef struct hurl_s {
struct {
unsigned short off;
unsigned short len;
} fields[HV_URL_FIELD_NUM];
unsigned short port;
} hurl_t;
HV_EXPORT int hv_parse_url(hurl_t* stURL, const char* strURL);
END_EXTERN_C
#endif // HV_BASE_H_

View File

@ -0,0 +1,257 @@
#ifndef HV_BUF_H_
#define HV_BUF_H_
#include "hdef.h" // for MAX
#include "hbase.h" // for HV_ALLOC, HV_FREE
typedef struct hbuf_s {
char* base;
size_t len;
#ifdef __cplusplus
hbuf_s() {
base = NULL;
len = 0;
}
hbuf_s(void* data, size_t len) {
this->base = (char*)data;
this->len = len;
}
#endif
} hbuf_t;
typedef struct offset_buf_s {
char* base;
size_t len;
size_t offset;
#ifdef __cplusplus
offset_buf_s() {
base = NULL;
len = 0;
offset = 0;
}
offset_buf_s(void* data, size_t len) {
this->base = (char*)data;
this->len = len;
offset = 0;
}
#endif
} offset_buf_t;
typedef struct fifo_buf_s {
char* base;
size_t len;
size_t head;
size_t tail;
#ifdef __cplusplus
fifo_buf_s() {
base = NULL;
len = 0;
head = tail = 0;
}
fifo_buf_s(void* data, size_t len) {
this->base = (char*)data;
this->len = len;
head = tail = 0;
}
#endif
} fifo_buf_t;
#ifdef __cplusplus
class HBuf : public hbuf_t {
public:
HBuf() : hbuf_t() {
cleanup_ = false;
}
HBuf(void* data, size_t len) : hbuf_t(data, len) {
cleanup_ = false;
}
HBuf(size_t cap) { resize(cap); }
virtual ~HBuf() {
cleanup();
}
void* data() { return base; }
size_t size() { return len; }
bool isNull() { return base == NULL || len == 0; }
void cleanup() {
if (cleanup_) {
HV_FREE(base);
len = 0;
cleanup_ = false;
}
}
void resize(size_t cap) {
if (cap == len) return;
if (base == NULL) {
HV_ALLOC(base, cap);
}
else {
base = (char*)hv_realloc(base, cap, len);
}
len = cap;
cleanup_ = true;
}
void copy(void* data, size_t len) {
resize(len);
memcpy(base, data, len);
}
void copy(hbuf_t* buf) {
copy(buf->base, buf->len);
}
private:
bool cleanup_;
};
// VL: Variable-Length
class HVLBuf : public HBuf {
public:
HVLBuf() : HBuf() {_offset = _size = 0;}
HVLBuf(void* data, size_t len) : HBuf(data, len) {_offset = 0; _size = len;}
HVLBuf(size_t cap) : HBuf(cap) {_offset = _size = 0;}
virtual ~HVLBuf() {}
char* data() { return base + _offset; }
size_t size() { return _size; }
void push_front(void* ptr, size_t len) {
if (len > this->len - _size) {
size_t newsize = MAX(this->len, len)*2;
resize(newsize);
}
if (_offset < len) {
// move => end
memmove(base+this->len-_size, data(), _size);
_offset = this->len-_size;
}
memcpy(data()-len, ptr, len);
_offset -= len;
_size += len;
}
void push_back(void* ptr, size_t len) {
if (len > this->len - _size) {
size_t newsize = MAX(this->len, len)*2;
resize(newsize);
}
else if (len > this->len - _offset - _size) {
// move => start
memmove(base, data(), _size);
_offset = 0;
}
memcpy(data()+_size, ptr, len);
_size += len;
}
void pop_front(void* ptr, size_t len) {
if (len <= _size) {
if (ptr) {
memcpy(ptr, data(), len);
}
_offset += len;
if (_offset >= this->len) _offset = 0;
_size -= len;
}
}
void pop_back(void* ptr, size_t len) {
if (len <= _size) {
if (ptr) {
memcpy(ptr, data()+_size-len, len);
}
_size -= len;
}
}
void clear() {
_offset = _size = 0;
}
void prepend(void* ptr, size_t len) {
push_front(ptr, len);
}
void append(void* ptr, size_t len) {
push_back(ptr, len);
}
void insert(void* ptr, size_t len) {
push_back(ptr, len);
}
void remove(size_t len) {
pop_front(NULL, len);
}
private:
size_t _offset;
size_t _size;
};
class HRingBuf : public HBuf {
public:
HRingBuf() : HBuf() {_head = _tail = _size = 0;}
HRingBuf(size_t cap) : HBuf(cap) {_head = _tail = _size = 0;}
virtual ~HRingBuf() {}
char* alloc(size_t len) {
char* ret = NULL;
if (_head < _tail || _size == 0) {
// [_tail, this->len) && [0, _head)
if (this->len - _tail >= len) {
ret = base + _tail;
_tail += len;
if (_tail == this->len) _tail = 0;
}
else if (_head >= len) {
ret = base;
_tail = len;
}
}
else {
// [_tail, _head)
if (_head - _tail >= len) {
ret = base + _tail;
_tail += len;
}
}
_size += ret ? len : 0;
return ret;
}
void free(size_t len) {
_size -= len;
if (len <= this->len - _head) {
_head += len;
if (_head == this->len) _head = 0;
}
else {
_head = len;
}
}
void clear() {_head = _tail = _size = 0;}
size_t size() {return _size;}
private:
size_t _head;
size_t _tail;
size_t _size;
};
#endif
#endif // HV_BUF_H_

View File

@ -0,0 +1,101 @@
#ifndef HV_CONFIG_H_
#define HV_CONFIG_H_
#ifndef HAVE_STDBOOL_H
#define HAVE_STDBOOL_H 1
#endif
#ifndef HAVE_STDINT_H
#define HAVE_STDINT_H 1
#endif
#ifndef HAVE_STDATOMIC_H
#define HAVE_STDATOMIC_H 0
#endif
#ifndef HAVE_SYS_TYPES_H
#define HAVE_SYS_TYPES_H 1
#endif
#ifndef HAVE_SYS_STAT_H
#define HAVE_SYS_STAT_H 1
#endif
#ifndef HAVE_SYS_TIME_H
#define HAVE_SYS_TIME_H 0
#endif
#ifndef HAVE_FCNTL_H
#define HAVE_FCNTL_H 1
#endif
#ifndef HAVE_PTHREAD_H
#define HAVE_PTHREAD_H 0
#endif
#ifndef HAVE_ENDIAN_H
#define HAVE_ENDIAN_H 0
#endif
#ifndef HAVE_SYS_ENDIAN_H
#define HAVE_SYS_ENDIAN_H 0
#endif
#ifndef HAVE_GETTID
#define HAVE_GETTID 0
#endif
#ifndef HAVE_STRLCPY
#define HAVE_STRLCPY 0
#endif
#ifndef HAVE_STRLCAT
#define HAVE_STRLCAT 0
#endif
#ifndef HAVE_CLOCK_GETTIME
#define HAVE_CLOCK_GETTIME 0
#endif
#ifndef HAVE_GETTIMEOFDAY
#define HAVE_GETTIMEOFDAY 0
#endif
#ifndef HAVE_PTHREAD_SPIN_LOCK
#define HAVE_PTHREAD_SPIN_LOCK 0
#endif
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
#define HAVE_PTHREAD_MUTEX_TIMEDLOCK 0
#endif
#ifndef HAVE_SEM_TIMEDWAIT
#define HAVE_SEM_TIMEDWAIT 0
#endif
#ifndef HAVE_PIPE
#define HAVE_PIPE 0
#endif
#ifndef HAVE_SOCKETPAIR
#define HAVE_SOCKETPAIR 0
#endif
#ifndef HAVE_EVENTFD
#define HAVE_EVENTFD 0
#endif
#ifndef HAVE_SETPROCTITLE
#define HAVE_SETPROCTITLE 0
#endif
#define WITH_OPENSSL 1
/* #undef WITH_GNUTLS */
/* #undef WITH_MBEDTLS */
/* #undef ENABLE_UDS */
/* #undef USE_MULTIMAP */
/* #undef WITH_KCP */
#endif // HV_CONFIG_H_

View File

@ -0,0 +1,270 @@
#ifndef HV_DEF_H_
#define HV_DEF_H_
#include "hplatform.h"
#ifndef ABS
#define ABS(n) ((n) > 0 ? (n) : -(n))
#endif
#ifndef NABS
#define NABS(n) ((n) < 0 ? (n) : -(n))
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
#endif
#ifndef BITSET
#define BITSET(p, n) (*(p) |= (1u << (n)))
#endif
#ifndef BITCLR
#define BITCLR(p, n) (*(p) &= ~(1u << (n)))
#endif
#ifndef BITGET
#define BITGET(i, n) ((i) & (1u << (n)))
#endif
/*
#ifndef CR
#define CR '\r'
#endif
#ifndef LF
#define LF '\n'
#endif
#ifndef CRLF
#define CRLF "\r\n"
#endif
*/
#define FLOAT_PRECISION 1e-6
#define FLOAT_EQUAL_ZERO(f) (ABS(f) < FLOAT_PRECISION)
#ifndef INFINITE
#define INFINITE (uint32_t)-1
#endif
/*
ASCII:
[0, 0x20) control-charaters
[0x20, 0x7F) printable-charaters
0x0A => LF
0x0D => CR
0x20 => SPACE
0x7F => DEL
[0x09, 0x0D] => \t\n\v\f\r
[0x30, 0x39] => 0~9
[0x41, 0x5A] => A~Z
[0x61, 0x7A] => a~z
*/
#ifndef IS_ALPHA
#define IS_ALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
#endif
#ifndef IS_NUM
#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
#endif
#ifndef IS_ALPHANUM
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
#endif
#ifndef IS_CNTRL
#define IS_CNTRL(c) ((c) >= 0 && (c) < 0x20)
#endif
#ifndef IS_GRAPH
#define IS_GRAPH(c) ((c) >= 0x20 && (c) < 0x7F)
#endif
#ifndef IS_HEX
#define IS_HEX(c) (IS_NUM(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
#endif
#ifndef IS_LOWER
#define IS_LOWER(c) (((c) >= 'a' && (c) <= 'z'))
#endif
#ifndef IS_UPPER
#define IS_UPPER(c) (((c) >= 'A' && (c) <= 'Z'))
#endif
#ifndef LOWER
#define LOWER(c) ((c) | 0x20)
#endif
#ifndef UPPER
#define UPPER(c) ((c) & ~0x20)
#endif
// LD, LU, LLD, LLU for explicit conversion of integer
// #ifndef LD
// #define LD(v) ((long)(v))
// #endif
// #ifndef LU
// #define LU(v) ((unsigned long)(v))
// #endif
#ifndef LLD
#define LLD(v) ((long long)(v))
#endif
#ifndef LLU
#define LLU(v) ((unsigned long long)(v))
#endif
#ifndef _WIN32
// MAKEWORD, HIBYTE, LOBYTE
#ifndef MAKEWORD
#define MAKEWORD(h, l) ( (((WORD)h) << 8) | (l & 0xff) )
#endif
#ifndef HIBYTE
#define HIBYTE(w) ( (BYTE)(((WORD)w) >> 8) )
#endif
#ifndef LOBYTE
#define LOBYTE(w) ( (BYTE)(w & 0xff) )
#endif
// MAKELONG, HIWORD, LOWORD
#ifndef MAKELONG
#define MAKELONG(h, l) ( ((int32_t)h) << 16 | (l & 0xffff) )
#endif
#ifndef HIWORD
#define HIWORD(n) ( (WORD)(((int32_t)n) >> 16) )
#endif
#ifndef LOWORD
#define LOWORD(n) ( (WORD)(n & 0xffff) )
#endif
#endif // _WIN32
// MAKEINT64, HIINT, LOINT
#ifndef MAKEINT64
#define MAKEINT64(h, l) ( ((int64_t)h) << 32 | (l & 0xffffffff) )
#endif
#ifndef HIINT
#define HIINT(n) ( (int32_t)(((int64_t)n) >> 32) )
#endif
#ifndef LOINT
#define LOINT(n) ( (int32_t)(n & 0xffffffff) )
#endif
#ifndef MAKE_FOURCC
#define MAKE_FOURCC(a, b, c, d) \
( ((uint32)d) | ( ((uint32)c) << 8 ) | ( ((uint32)b) << 16 ) | ( ((uint32)a) << 24 ) )
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef LIMIT
#define LIMIT(lower, v, upper) ((v) < (lower) ? (lower) : (v) > (upper) ? (upper) : (v))
#endif
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef SAFE_ALLOC
#define SAFE_ALLOC(p, size)\
do {\
void* ptr = malloc(size);\
if (!ptr) {\
fprintf(stderr, "malloc failed!\n");\
exit(-1);\
}\
memset(ptr, 0, size);\
*(void**)&(p) = ptr;\
} while(0)
#endif
#ifndef SAFE_FREE
#define SAFE_FREE(p) do {if (p) {free(p); (p) = NULL;}} while(0)
#endif
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) do {if (p) {delete (p); (p) = NULL;}} while(0)
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) do {if (p) {delete[] (p); (p) = NULL;}} while(0)
#endif
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) do {if (p) {(p)->release(); (p) = NULL;}} while(0)
#endif
#ifndef SAFE_CLOSE
#define SAFE_CLOSE(fd) do {if ((fd) >= 0) {close(fd); (fd) = -1;}} while(0)
#endif
#define STRINGIFY(x) STRINGIFY_HELPER(x)
#define STRINGIFY_HELPER(x) #x
#define STRINGCAT(x, y) STRINGCAT_HELPER(x, y)
#define STRINGCAT_HELPER(x, y) x##y
#ifndef offsetof
#define offsetof(type, member) \
((size_t)(&((type*)0)->member))
#endif
#ifndef offsetofend
#define offsetofend(type, member) \
(offsetof(type, member) + sizeof(((type*)0)->member))
#endif
#ifndef container_of
#define container_of(ptr, type, member) \
((type*)((char*)(ptr) - offsetof(type, member)))
#endif
#ifdef PRINT_DEBUG
#define printd(...) printf(__VA_ARGS__)
#else
#define printd(...)
#endif
#ifdef PRINT_ERROR
#define printe(...) fprintf(stderr, __VA_ARGS__)
#else
#define printe(...)
#endif
#endif // HV_DEF_H_

View File

@ -0,0 +1,69 @@
#ifndef HV_DIR_H_
#define HV_DIR_H_
/*
*@code
int main(int argc, char* argv[]) {
const char* dir = ".";
if (argc > 1) {
dir = argv[1];
}
std::list<hdir_t> dirs;
listdir(dir, dirs);
for (auto& item : dirs) {
printf("%c%c%c%c%c%c%c%c%c%c\t",
item.type,
item.mode & 0400 ? 'r' : '-',
item.mode & 0200 ? 'w' : '-',
item.mode & 0100 ? 'x' : '-',
item.mode & 0040 ? 'r' : '-',
item.mode & 0020 ? 'w' : '-',
item.mode & 0010 ? 'x' : '-',
item.mode & 0004 ? 'r' : '-',
item.mode & 0002 ? 'w' : '-',
item.mode & 0001 ? 'x' : '-');
float hsize;
if (item.size < 1024) {
printf("%lu\t", item.size);
}
else if ((hsize = item.size/1024.0f) < 1024.0f) {
printf("%.1fK\t", hsize);
}
else if ((hsize /= 1024.0f) < 1024.0f) {
printf("%.1fM\t", hsize);
}
else {
hsize /= 1024.0f;
printf("%.1fG\t", hsize);
}
struct tm* tm = localtime(&item.mtime);
printf("%04d-%02d-%02d %02d:%02d:%02d\t",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
printf("%s%s\n", item.name, item.type == 'd' ? "/" : "");
}
return 0;
}
*/
#include <string.h>
#include <time.h>
#include <list>
#include "hexport.h"
typedef struct hdir_s {
char name[256];
char type; // f:file d:dir l:link b:block c:char s:socket p:pipe
char reserverd;
unsigned short mode;
size_t size;
time_t atime;
time_t mtime;
time_t ctime;
} hdir_t;
// listdir: same as ls on unix, dir on win
HV_EXPORT int listdir(const char* dir, std::list<hdir_t>& dirs);
#endif // HV_DIR_H_

View File

@ -0,0 +1,161 @@
#ifndef HV_ENDIAN_H_
#define HV_ENDIAN_H_
#include "hplatform.h"
#if defined(OS_MAC)
#include <libkern/OSByteOrder.h>
#define htobe16(v) OSSwapHostToBigInt16(v)
#define htobe32(v) OSSwapHostToBigInt32(v)
#define htobe64(v) OSSwapHostToBigInt64(v)
#define be16toh(v) OSSwapBigToHostInt16(v)
#define be32toh(v) OSSwapBigToHostInt32(v)
#define be64toh(v) OSSwapBigToHostInt64(v)
#define htole16(v) OSSwapHostToLittleInt16(v)
#define htole32(v) OSSwapHostToLittleInt32(v)
#define htole64(v) OSSwapHostToLittleInt64(v)
#define le16toh(v) OSSwapLittleToHostInt16(v)
#define le32toh(v) OSSwapLittleToHostInt32(v)
#define le64toh(v) OSSwapLittleToHostInt64(v)
#elif defined(OS_WIN)
#define htobe16(v) htons(v)
#define htobe32(v) htonl(v)
#define htobe64(v) htonll(v)
#define be16toh(v) ntohs(v)
#define be32toh(v) ntohl(v)
#define be64toh(v) ntohll(v)
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define htole16(v) (v)
#define htole32(v) (v)
#define htole64(v) (v)
#define le16toh(v) (v)
#define le32toh(v) (v)
#define le64toh(v) (v)
#elif (BYTE_ORDER == BIG_ENDIAN)
#define htole16(v) __builtin_bswap16(v)
#define htole32(v) __builtin_bswap32(v)
#define htole64(v) __builtin_bswap64(v)
#define le16toh(v) __builtin_bswap16(v)
#define le32toh(v) __builtin_bswap32(v)
#define le64toh(v) __builtin_bswap64(v)
#endif
#elif HAVE_ENDIAN_H
#include <endian.h>
#elif HAVE_SYS_ENDIAN_H
#include <sys/endian.h>
#else
#warning "Not found endian.h!"
#endif
#define PI8(p) *(int8_t*)(p)
#define PI16(p) *(int16_t*)(p)
#define PI32(p) *(int32_t*)(p)
#define PI64(p) *(int64_t*)(p)
#define PU8(p) *(uint8_t*)(p)
#define PU16(p) *(uint16_t*)(p)
#define PU32(p) *(uint32_t*)(p)
#define PU64(p) *(uint64_t*)(p)
#define PF32(p) *(float*)(p)
#define PF64(p) *(double*)(p)
#define GET_BE16(p) be16toh(PU16(p))
#define GET_BE32(p) be32toh(PU32(p))
#define GET_BE64(p) be64toh(PU64(p))
#define GET_LE16(p) le16toh(PU16(p))
#define GET_LE32(p) le32toh(PU32(p))
#define GET_LE64(p) le64toh(PU64(p))
#define PUT_BE16(p, v) PU16(p) = htobe16(v)
#define PUT_BE32(p, v) PU32(p) = htobe32(v)
#define PUT_BE64(p, v) PU64(p) = htobe64(v)
#define PUT_LE16(p, v) PU16(p) = htole16(v)
#define PUT_LE32(p, v) PU32(p) = htole32(v)
#define PUT_LE64(p, v) PU64(p) = htole64(v)
// NOTE: uint8_t* p = (uint8_t*)buf;
#define POP_BE8(p, v) v = *p; ++p
#define POP_BE16(p, v) v = be16toh(PU16(p)); p += 2
#define POP_BE32(p, v) v = be32toh(PU32(p)); p += 4
#define POP_BE64(p, v) v = be64toh(PU64(p)); p += 8
#define POP_LE8(p, v) v= *p; ++p
#define POP_LE16(p, v) v = le16toh(PU16(p)); p += 2
#define POP_LE32(p, v) v = le32toh(PU32(p)); p += 4
#define POP_LE64(p, v) v = le64toh(PU64(p)); p += 8
#define PUSH_BE8(p, v) *p = v; ++p
#define PUSH_BE16(p, v) PU16(p) = htobe16(v); p += 2
#define PUSH_BE32(p, v) PU32(p) = htobe32(v); p += 4
#define PUSH_BE64(p, v) PU64(p) = htobe64(v); p += 8
#define PUSH_LE8(p, v) *p = v; ++p
#define PUSH_LE16(p, v) PU16(p) = htole16(v); p += 2
#define PUSH_LE32(p, v) PU32(p) = htole32(v); p += 4
#define PUSH_LE64(p, v) PU64(p) = htole64(v); p += 8
// NOTE: NET_ENDIAN = BIG_ENDIAN
#define POP8(p, v) POP_BE8(p, v)
#define POP16(p, v) POP_BE16(p, v)
#define POP32(p, v) POP_BE32(p, v)
#define POP64(p, v) POP_BE64(p, v)
#define POP_N(p, v, n) memcpy(v, p, n); p += n
#define PUSH8(p, v) PUSH_BE8(p, v)
#define PUSH16(p, v) PUSH_BE16(p, v)
#define PUSH32(p, v) PUSH_BE32(p, v)
#define PUSH64(p, v) PUSH_BE64(p, v)
#define PUSH_N(p, v, n) memcpy(p, v, n); p += n
static inline int detect_endian() {
union {
char c;
short s;
} u;
u.s = 0x1122;
return u.c ==0x11 ? BIG_ENDIAN : LITTLE_ENDIAN;
}
#ifdef __cplusplus
template <typename T>
uint8_t* serialize(uint8_t* buf, T value, int host_endian = LITTLE_ENDIAN, int buf_endian = BIG_ENDIAN) {
size_t size = sizeof(T);
uint8_t* pDst = buf;
uint8_t* pSrc = (uint8_t*)&value;
if (host_endian == buf_endian) {
memcpy(pDst, pSrc, size);
}
else {
for (int i = 0; i < size; ++i) {
pDst[i] = pSrc[size-i-1];
}
}
return buf+size;
}
template <typename T>
uint8_t* deserialize(uint8_t* buf, T* value, int host_endian = LITTLE_ENDIAN, int buf_endian = BIG_ENDIAN) {
size_t size = sizeof(T);
uint8_t* pSrc = buf;
uint8_t* pDst = (uint8_t*)value;
if (host_endian == buf_endian) {
memcpy(pDst, pSrc, size);
}
else {
for (int i = 0; i < size; ++i) {
pDst[i] = pSrc[size-i-1];
}
}
return buf+size;
}
#endif // __cplusplus
#endif // HV_ENDIAN_H_

View File

@ -0,0 +1,122 @@
#ifndef HV_ERR_H_
#define HV_ERR_H_
#include <errno.h>
#include "hexport.h"
#ifndef SYS_NERR
#define SYS_NERR 133
#endif
// F(errcode, name, errmsg)
// [1, 133]
#define FOREACH_ERR_SYS(F)
// [1xx~5xx]
#define FOREACH_ERR_STATUS(F)
// [1xxx]
#define FOREACH_ERR_COMMON(F) \
F(0, OK, "OK") \
F(1000, UNKNOWN, "Unknown error") \
\
F(1001, NULL_PARAM, "Null parameter") \
F(1002, NULL_POINTER, "Null pointer") \
F(1003, NULL_DATA, "Null data") \
F(1004, NULL_HANDLE, "Null handle") \
\
F(1011, INVALID_PARAM, "Invalid parameter")\
F(1012, INVALID_POINTER, "Invalid pointer") \
F(1013, INVALID_DATA, "Invalid data") \
F(1014, INVALID_HANDLE, "Invalid handle") \
F(1015, INVALID_JSON, "Invalid json") \
F(1016, INVALID_XML, "Invalid xml") \
F(1017, INVALID_FMT, "Invalid format") \
F(1018, INVALID_PROTOCOL, "Invalid protocol") \
F(1019, INVALID_PACKAGE, "Invalid package") \
\
F(1021, OUT_OF_RANGE, "Out of range") \
F(1022, OVER_LIMIT, "Over the limit") \
F(1023, MISMATCH, "Mismatch") \
F(1024, PARSE, "Parse failed") \
\
F(1030, OPEN_FILE, "Open file failed") \
F(1031, SAVE_FILE, "Save file failed") \
F(1032, READ_FILE, "Read file failed") \
F(1033, WRITE_FILE, "Write file failed")\
\
F(1040, SSL, "SSL/TLS error") \
F(1041, NEW_SSL_CTX, "New SSL_CTX failed") \
F(1042, NEW_SSL, "New SSL failed") \
F(1043, SSL_HANDSHAKE, "SSL handshake failed") \
\
F(1100, TASK_TIMEOUT, "Task timeout") \
F(1101, TASK_QUEUE_FULL, "Task queue full") \
F(1102, TASK_QUEUE_EMPTY, "Task queue empty") \
\
F(1400, REQUEST, "Bad request") \
F(1401, RESPONSE, "Bad response") \
// [-1xxx]
#define FOREACH_ERR_FUNC(F) \
F(-1001, MALLOC, "malloc() error") \
F(-1002, REALLOC, "realloc() error") \
F(-1003, CALLOC, "calloc() error") \
F(-1004, FREE, "free() error") \
\
F(-1011, SOCKET, "socket() error") \
F(-1012, BIND, "bind() error") \
F(-1013, LISTEN, "listen() error") \
F(-1014, ACCEPT, "accept() error") \
F(-1015, CONNECT, "connect() error") \
F(-1016, RECV, "recv() error") \
F(-1017, SEND, "send() error") \
F(-1018, RECVFROM, "recvfrom() error") \
F(-1019, SENDTO, "sendto() error") \
F(-1020, SETSOCKOPT, "setsockopt() error") \
F(-1021, GETSOCKOPT, "getsockopt() error") \
// grpc [4xxx]
#define FOREACH_ERR_GRPC(F) \
F(4000, GRPC_FIRST, "grpc no error") \
F(4001, GRPC_STATUS_CANCELLED, "grpc status: cancelled") \
F(4002, GRPC_STATUS_UNKNOWN, "grpc unknown error") \
F(4003, GRPC_STATUS_INVALID_ARGUMENT, "grpc status: invalid argument")\
F(4004, GRPC_STATUS_DEADLINE, "grpc status: deadline") \
F(4005, GRPC_STATUS_NOT_FOUND, "grpc status: not found") \
F(4006, GRPC_STATUS_ALREADY_EXISTS, "grpc status: already exists") \
F(4007, GRPC_STATUS_PERMISSION_DENIED, "grpc status: permission denied") \
F(4008, GRPC_STATUS_RESOURCE_EXHAUSTED, "grpc status: resource exhausted") \
F(4009, GRPC_STATUS_FAILED_PRECONDITION,"grpc status: failed precondition") \
F(4010, GRPC_STATUS_ABORTED, "grpc status: aborted") \
F(4011, GRPC_STATUS_OUT_OF_RANGE, "grpc status: out of range") \
F(4012, GRPC_STATUS_UNIMPLEMENTED, "grpc status: unimplemented") \
F(4013, GRPC_STATUS_INTERNAL, "grpc internal error") \
F(4014, GRPC_STATUS_UNAVAILABLE, "grpc service unavailable") \
F(4015, GRPC_STATUS_DATA_LOSS, "grpc status: data loss") \
#define FOREACH_ERR(F) \
FOREACH_ERR_COMMON(F) \
FOREACH_ERR_FUNC(F) \
FOREACH_ERR_GRPC(F) \
#undef ERR_OK // prevent conflict
enum {
#define F(errcode, name, errmsg) ERR_##name = errcode,
FOREACH_ERR(F)
#undef F
};
#ifdef __cplusplus
extern "C" {
#endif
// errcode => errmsg
HV_EXPORT const char* hv_strerror(int err);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // HV_ERR_H_

View File

@ -0,0 +1,153 @@
#ifndef HV_EXPORT_H_
#define HV_EXPORT_H_
// HV_EXPORT
#if defined(HV_STATICLIB) || defined(HV_SOURCE)
#define HV_EXPORT
#elif defined(_MSC_VER)
#if defined(HV_DYNAMICLIB) || defined(HV_EXPORTS) || defined(hv_EXPORTS)
#define HV_EXPORT __declspec(dllexport)
#else
#define HV_EXPORT __declspec(dllimport)
#endif
#elif defined(__GNUC__)
#define HV_EXPORT __attribute__((visibility("default")))
#else
#define HV_EXPORT
#endif
// HV_INLINE
#define HV_INLINE static inline
// HV_DEPRECATED
#if defined(HV_NO_DEPRECATED)
#define HV_DEPRECATED
#elif defined(__GNUC__) || defined(__clang__)
#define HV_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define HV_DEPRECATED __declspec(deprecated)
#else
#define HV_DEPRECATED
#endif
// HV_UNUSED
#if defined(__GNUC__)
#define HV_UNUSED __attribute__((visibility("unused")))
#else
#define HV_UNUSED
#endif
// @param[IN | OUT | INOUT]
#ifndef IN
#define IN
#endif
#ifndef OUT
#define OUT
#endif
#ifndef INOUT
#define INOUT
#endif
// @field[OPTIONAL | REQUIRED | REPEATED]
#ifndef OPTIONAL
#define OPTIONAL
#endif
#ifndef REQUIRED
#define REQUIRED
#endif
#ifndef REPEATED
#define REPEATED
#endif
#ifdef __cplusplus
#ifndef EXTERN_C
#define EXTERN_C extern "C"
#endif
#ifndef BEGIN_EXTERN_C
#define BEGIN_EXTERN_C extern "C" {
#endif
#ifndef END_EXTERN_C
#define END_EXTERN_C } // extern "C"
#endif
#ifndef BEGIN_NAMESPACE
#define BEGIN_NAMESPACE(ns) namespace ns {
#endif
#ifndef END_NAMESPACE
#define END_NAMESPACE(ns) } // namespace ns
#endif
#ifndef USING_NAMESPACE
#define USING_NAMESPACE(ns) using namespace ns;
#endif
#ifndef DEFAULT
#define DEFAULT(x) = x
#endif
#ifndef ENUM
#define ENUM(e) enum e
#endif
#ifndef STRUCT
#define STRUCT(s) struct s
#endif
#else
#define EXTERN_C extern
#define BEGIN_EXTERN_C
#define END_EXTERN_C
#define BEGIN_NAMESPACE(ns)
#define END_NAMESPACE(ns)
#define USING_NAMESPACE(ns)
#ifndef DEFAULT
#define DEFAULT(x)
#endif
#ifndef ENUM
#define ENUM(e)\
typedef enum e e;\
enum e
#endif
#ifndef STRUCT
#define STRUCT(s)\
typedef struct s s;\
struct s
#endif
#endif // __cplusplus
#define BEGIN_NAMESPACE_HV BEGIN_NAMESPACE(hv)
#define END_NAMESPACE_HV END_NAMESPACE(hv)
#define USING_NAMESPACE_HV USING_NAMESPACE(hv)
// MSVC ports
#ifdef _MSC_VER
#if _MSC_VER < 1900 // < VS2015
#ifndef __cplusplus
#ifndef inline
#define inline __inline
#endif
#endif
#ifndef snprintf
#define snprintf _snprintf
#endif
#endif
#endif
#endif // HV_EXPORT_H_

View File

@ -0,0 +1,123 @@
#ifndef HV_FILE_H_
#define HV_FILE_H_
#include <string> // for std::string
#include "hplatform.h" // for stat
#include "hbuf.h" // for HBuf
class HFile {
public:
HFile() {
fp = NULL;
}
~HFile() {
close();
}
int open(const char* filepath, const char* mode) {
close();
strncpy(this->filepath, filepath, MAX_PATH);
fp = fopen(filepath, mode);
return fp ? 0 : errno;
}
void close() {
if (fp) {
fclose(fp);
fp = NULL;
}
}
bool isopen() {
return fp != NULL;
}
size_t read(void* ptr, size_t len) {
return fread(ptr, 1, len, fp);
}
size_t write(const void* ptr, size_t len) {
return fwrite(ptr, 1, len, fp);
}
size_t write(const std::string& str) {
return write(str.c_str(), str.length());
}
int seek(size_t offset, int whence = SEEK_SET) {
return fseek(fp, offset, whence);
}
int tell() {
return ftell(fp);
}
int flush() {
return fflush(fp);
}
static size_t size(const char* filepath) {
struct stat st;
memset(&st, 0, sizeof(st));
stat(filepath, &st);
return st.st_size;
}
size_t size() {
return HFile::size(filepath);
}
size_t readall(HBuf& buf) {
size_t filesize = size();
if (filesize == 0) return 0;
buf.resize(filesize);
return fread(buf.base, 1, filesize, fp);
}
size_t readall(std::string& str) {
size_t filesize = size();
if (filesize == 0) return 0;
str.resize(filesize);
return fread((void*)str.data(), 1, filesize, fp);
}
bool readline(std::string& str) {
str.clear();
char ch;
while (fread(&ch, 1, 1, fp)) {
if (ch == '\n') {
// unix: LF
return true;
}
if (ch == '\r') {
// dos: CRLF
// read LF
if (fread(&ch, 1, 1, fp) && ch != '\n') {
// mac: CR
fseek(fp, -1, SEEK_CUR);
}
return true;
}
str += ch;
}
return str.length() != 0;
}
int readrange(std::string& str, size_t from = 0, size_t to = 0) {
size_t filesize = size();
if (filesize == 0) return 0;
if (to == 0 || to >= filesize) to = filesize - 1;
size_t readbytes = to - from + 1;
str.resize(readbytes);
fseek(fp, from, SEEK_SET);
return fread((void*)str.data(), 1, readbytes, fp);
}
public:
char filepath[MAX_PATH];
FILE* fp;
};
#endif // HV_FILE_H_

View File

@ -0,0 +1,176 @@
#ifndef HV_LOG_H_
#define HV_LOG_H_
/*
* hlog is thread-safe
*/
#include <string.h>
#ifdef _WIN32
#define DIR_SEPARATOR '\\'
#define DIR_SEPARATOR_STR "\\"
#else
#define DIR_SEPARATOR '/'
#define DIR_SEPARATOR_STR "/"
#endif
#ifndef __FILENAME__
// #define __FILENAME__ (strrchr(__FILE__, DIR_SEPARATOR) ? strrchr(__FILE__, DIR_SEPARATOR) + 1 : __FILE__)
#define __FILENAME__ (strrchr(DIR_SEPARATOR_STR __FILE__, DIR_SEPARATOR) + 1)
#endif
#include "hexport.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CLR_CLR "\033[0m" /* 恢复颜色 */
#define CLR_BLACK "\033[30m" /* 黑色字 */
#define CLR_RED "\033[31m" /* 红色字 */
#define CLR_GREEN "\033[32m" /* 绿色字 */
#define CLR_YELLOW "\033[33m" /* 黄色字 */
#define CLR_BLUE "\033[34m" /* 蓝色字 */
#define CLR_PURPLE "\033[35m" /* 紫色字 */
#define CLR_SKYBLUE "\033[36m" /* 天蓝字 */
#define CLR_WHITE "\033[37m" /* 白色字 */
#define CLR_BLK_WHT "\033[40;37m" /* 黑底白字 */
#define CLR_RED_WHT "\033[41;37m" /* 红底白字 */
#define CLR_GREEN_WHT "\033[42;37m" /* 绿底白字 */
#define CLR_YELLOW_WHT "\033[43;37m" /* 黄底白字 */
#define CLR_BLUE_WHT "\033[44;37m" /* 蓝底白字 */
#define CLR_PURPLE_WHT "\033[45;37m" /* 紫底白字 */
#define CLR_SKYBLUE_WHT "\033[46;37m" /* 天蓝底白字 */
#define CLR_WHT_BLK "\033[47;30m" /* 白底黑字 */
// XXX(id, str, clr)
#define LOG_LEVEL_MAP(XXX) \
XXX(LOG_LEVEL_DEBUG, "DEBUG", CLR_WHITE) \
XXX(LOG_LEVEL_INFO, "INFO ", CLR_GREEN) \
XXX(LOG_LEVEL_WARN, "WARN ", CLR_YELLOW) \
XXX(LOG_LEVEL_ERROR, "ERROR", CLR_RED) \
XXX(LOG_LEVEL_FATAL, "FATAL", CLR_RED_WHT)
typedef enum {
LOG_LEVEL_VERBOSE = 0,
#define XXX(id, str, clr) id,
LOG_LEVEL_MAP(XXX)
#undef XXX
LOG_LEVEL_SILENT
} log_level_e;
#define DEFAULT_LOG_FILE "libhv"
#define DEFAULT_LOG_LEVEL LOG_LEVEL_INFO
#define DEFAULT_LOG_FORMAT "%y-%m-%d %H:%M:%S.%z %L %s"
#define DEFAULT_LOG_REMAIN_DAYS 1
#define DEFAULT_LOG_MAX_BUFSIZE (1<<14) // 16k
#define DEFAULT_LOG_MAX_FILESIZE (1<<24) // 16M
// logger: default file_logger
// network_logger() see event/nlog.h
typedef void (*logger_handler)(int loglevel, const char* buf, int len);
HV_EXPORT void stdout_logger(int loglevel, const char* buf, int len);
HV_EXPORT void stderr_logger(int loglevel, const char* buf, int len);
HV_EXPORT void file_logger(int loglevel, const char* buf, int len);
// network_logger implement see event/nlog.h
// HV_EXPORT void network_logger(int loglevel, const char* buf, int len);
typedef struct logger_s logger_t;
HV_EXPORT logger_t* logger_create();
HV_EXPORT void logger_destroy(logger_t* logger);
HV_EXPORT void logger_set_handler(logger_t* logger, logger_handler fn);
HV_EXPORT void logger_set_level(logger_t* logger, int level);
// level = [VERBOSE,DEBUG,INFO,WARN,ERROR,FATAL,SILENT]
HV_EXPORT void logger_set_level_by_str(logger_t* logger, const char* level);
/*
* format = "%y-%m-%d %H:%M:%S.%z %L %s"
* message = "2020-01-02 03:04:05.067 DEBUG message"
* %y year
* %m month
* %d day
* %H hour
* %M min
* %S sec
* %z ms
* %Z us
* %l First character of level
* %L All characters of level
* %s message
* %% %
*/
HV_EXPORT void logger_set_format(logger_t* logger, const char* format);
HV_EXPORT void logger_set_max_bufsize(logger_t* logger, unsigned int bufsize);
HV_EXPORT void logger_enable_color(logger_t* logger, int on);
HV_EXPORT int logger_print(logger_t* logger, int level, const char* fmt, ...);
// below for file logger
HV_EXPORT void logger_set_file(logger_t* logger, const char* filepath);
HV_EXPORT void logger_set_max_filesize(logger_t* logger, unsigned long long filesize);
// 16, 16M, 16MB
HV_EXPORT void logger_set_max_filesize_by_str(logger_t* logger, const char* filesize);
HV_EXPORT void logger_set_remain_days(logger_t* logger, int days);
HV_EXPORT void logger_enable_fsync(logger_t* logger, int on);
HV_EXPORT void logger_fsync(logger_t* logger);
HV_EXPORT const char* logger_get_cur_file(logger_t* logger);
// hlog: default logger instance
HV_EXPORT logger_t* hv_default_logger();
HV_EXPORT void hv_destroy_default_logger();
// macro hlog*
#define hlog hv_default_logger()
#define hlog_destory() hv_destroy_default_logger()
#define hlog_disable() logger_set_level(hlog, LOG_LEVEL_SILENT)
#define hlog_set_file(filepath) logger_set_file(hlog, filepath)
#define hlog_set_level(level) logger_set_level(hlog, level)
#define hlog_set_level_by_str(level) logger_set_level_by_str(hlog, level)
#define hlog_set_handler(fn) logger_set_handler(hlog, fn)
#define hlog_set_format(format) logger_set_format(hlog, format)
#define hlog_set_max_filesize(filesize) logger_set_max_filesize(hlog, filesize)
#define hlog_set_max_filesize_by_str(filesize) logger_set_max_filesize_by_str(hlog, filesize)
#define hlog_set_remain_days(days) logger_set_remain_days(hlog, days)
#define hlog_enable_fsync() logger_enable_fsync(hlog, 1)
#define hlog_disable_fsync() logger_enable_fsync(hlog, 0)
#define hlog_fsync() logger_fsync(hlog)
#define hlog_get_cur_file() logger_get_cur_file(hlog)
#define hlogd(fmt, ...) logger_print(hlog, LOG_LEVEL_DEBUG, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
#define hlogi(fmt, ...) logger_print(hlog, LOG_LEVEL_INFO, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
#define hlogw(fmt, ...) logger_print(hlog, LOG_LEVEL_WARN, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
#define hloge(fmt, ...) logger_print(hlog, LOG_LEVEL_ERROR, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
#define hlogf(fmt, ...) logger_print(hlog, LOG_LEVEL_FATAL, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
// below for android
#if defined(ANDROID) || defined(__ANDROID__)
#include <android/log.h>
#define LOG_TAG "JNI"
#undef hlogd
#undef hlogi
#undef hlogw
#undef hloge
#undef hlogf
#define hlogd(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define hlogi(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define hlogw(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define hloge(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define hlogf(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
#endif
// macro alias
#if !defined(LOGD) && !defined(LOGI) && !defined(LOGW) && !defined(LOGE) && !defined(LOGF)
#define LOGD hlogd
#define LOGI hlogi
#define LOGW hlogw
#define LOGE hloge
#define LOGF hlogf
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif // HV_LOG_H_

View File

@ -0,0 +1,700 @@
#ifndef HV_LOOP_H_
#define HV_LOOP_H_
#include "hexport.h"
#include "hplatform.h"
#include "hdef.h"
#include "hssl.h"
typedef struct hloop_s hloop_t;
typedef struct hevent_s hevent_t;
// NOTE: The following structures are subclasses of hevent_t,
// inheriting hevent_t data members and function members.
typedef struct hidle_s hidle_t;
typedef struct htimer_s htimer_t;
typedef struct htimeout_s htimeout_t;
typedef struct hperiod_s hperiod_t;
typedef struct hio_s hio_t;
typedef void (*hevent_cb) (hevent_t* ev);
typedef void (*hidle_cb) (hidle_t* idle);
typedef void (*htimer_cb) (htimer_t* timer);
typedef void (*hio_cb) (hio_t* io);
typedef void (*haccept_cb) (hio_t* io);
typedef void (*hconnect_cb) (hio_t* io);
typedef void (*hread_cb) (hio_t* io, void* buf, int readbytes);
typedef void (*hwrite_cb) (hio_t* io, const void* buf, int writebytes);
typedef void (*hclose_cb) (hio_t* io);
typedef enum {
HLOOP_STATUS_STOP,
HLOOP_STATUS_RUNNING,
HLOOP_STATUS_PAUSE
} hloop_status_e;
typedef enum {
HEVENT_TYPE_NONE = 0,
HEVENT_TYPE_IO = 0x00000001,
HEVENT_TYPE_TIMEOUT = 0x00000010,
HEVENT_TYPE_PERIOD = 0x00000020,
HEVENT_TYPE_TIMER = HEVENT_TYPE_TIMEOUT|HEVENT_TYPE_PERIOD,
HEVENT_TYPE_IDLE = 0x00000100,
HEVENT_TYPE_CUSTOM = 0x00000400, // 1024
} hevent_type_e;
#define HEVENT_LOWEST_PRIORITY (-5)
#define HEVENT_LOW_PRIORITY (-3)
#define HEVENT_NORMAL_PRIORITY 0
#define HEVENT_HIGH_PRIORITY 3
#define HEVENT_HIGHEST_PRIORITY 5
#define HEVENT_PRIORITY_SIZE (HEVENT_HIGHEST_PRIORITY-HEVENT_LOWEST_PRIORITY+1)
#define HEVENT_PRIORITY_INDEX(priority) (priority-HEVENT_LOWEST_PRIORITY)
#define HEVENT_FLAGS \
unsigned destroy :1; \
unsigned active :1; \
unsigned pending :1;
#define HEVENT_FIELDS \
hloop_t* loop; \
hevent_type_e event_type; \
uint64_t event_id; \
hevent_cb cb; \
void* userdata; \
void* privdata; \
struct hevent_s* pending_next; \
int priority; \
HEVENT_FLAGS
// sizeof(struct hevent_s)=64 on x64
struct hevent_s {
HEVENT_FIELDS
};
#define hevent_set_id(ev, id) ((hevent_t*)(ev))->event_id = id
#define hevent_set_cb(ev, cb) ((hevent_t*)(ev))->cb = cb
#define hevent_set_priority(ev, prio) ((hevent_t*)(ev))->priority = prio
#define hevent_set_userdata(ev, udata) ((hevent_t*)(ev))->userdata = (void*)udata
#define hevent_loop(ev) (((hevent_t*)(ev))->loop)
#define hevent_type(ev) (((hevent_t*)(ev))->event_type)
#define hevent_id(ev) (((hevent_t*)(ev))->event_id)
#define hevent_cb(ev) (((hevent_t*)(ev))->cb)
#define hevent_priority(ev) (((hevent_t*)(ev))->priority)
#define hevent_userdata(ev) (((hevent_t*)(ev))->userdata)
typedef enum {
HIO_TYPE_UNKNOWN = 0,
HIO_TYPE_STDIN = 0x00000001,
HIO_TYPE_STDOUT = 0x00000002,
HIO_TYPE_STDERR = 0x00000004,
HIO_TYPE_STDIO = 0x0000000F,
HIO_TYPE_FILE = 0x00000010,
HIO_TYPE_IP = 0x00000100,
HIO_TYPE_SOCK_RAW = 0x00000F00,
HIO_TYPE_UDP = 0x00001000,
HIO_TYPE_KCP = 0x00002000,
HIO_TYPE_DTLS = 0x00010000,
HIO_TYPE_SOCK_DGRAM = 0x000FF000,
HIO_TYPE_TCP = 0x00100000,
HIO_TYPE_SSL = 0x01000000,
HIO_TYPE_TLS = HIO_TYPE_SSL,
HIO_TYPE_SOCK_STREAM= 0x0FF00000,
HIO_TYPE_SOCKET = 0x0FFFFF00,
} hio_type_e;
typedef enum {
HIO_SERVER_SIDE = 0,
HIO_CLIENT_SIDE = 1,
} hio_side_e;
#define HIO_DEFAULT_CONNECT_TIMEOUT 10000 // ms
#define HIO_DEFAULT_CLOSE_TIMEOUT 60000 // ms
#define HIO_DEFAULT_KEEPALIVE_TIMEOUT 75000 // ms
#define HIO_DEFAULT_HEARTBEAT_INTERVAL 10000 // ms
BEGIN_EXTERN_C
// loop
#define HLOOP_FLAG_RUN_ONCE 0x00000001
#define HLOOP_FLAG_AUTO_FREE 0x00000002
#define HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS 0x00000004
HV_EXPORT hloop_t* hloop_new(int flags DEFAULT(HLOOP_FLAG_AUTO_FREE));
// WARN: Forbid to call hloop_free if HLOOP_FLAG_AUTO_FREE set.
HV_EXPORT void hloop_free(hloop_t** pp);
// NOTE: when no active events, loop will quit if HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS set.
HV_EXPORT int hloop_run(hloop_t* loop);
// NOTE: hloop_stop called in loop-thread just set flag to quit in next loop,
// if called in other thread, it will wakeup loop-thread from blocking poll system call,
// then you should join loop thread to safely exit loop thread.
HV_EXPORT int hloop_stop(hloop_t* loop);
HV_EXPORT int hloop_pause(hloop_t* loop);
HV_EXPORT int hloop_resume(hloop_t* loop);
HV_EXPORT int hloop_wakeup(hloop_t* loop);
HV_EXPORT hloop_status_e hloop_status(hloop_t* loop);
HV_EXPORT void hloop_update_time(hloop_t* loop);
HV_EXPORT uint64_t hloop_now(hloop_t* loop); // s
HV_EXPORT uint64_t hloop_now_ms(hloop_t* loop); // ms
HV_EXPORT uint64_t hloop_now_us(hloop_t* loop); // us
HV_EXPORT uint64_t hloop_now_hrtime(hloop_t* loop); // us
// export some hloop's members
// @return pid of hloop_run
HV_EXPORT long hloop_pid(hloop_t* loop);
// @return tid of hloop_run
HV_EXPORT long hloop_tid(hloop_t* loop);
// @return count of loop
HV_EXPORT uint64_t hloop_count(hloop_t* loop);
// @return number of ios
HV_EXPORT uint32_t hloop_nios(hloop_t* loop);
// @return number of timers
HV_EXPORT uint32_t hloop_ntimers(hloop_t* loop);
// @return number of idles
HV_EXPORT uint32_t hloop_nidles(hloop_t* loop);
// @return number of active events
HV_EXPORT uint32_t hloop_nactives(hloop_t* loop);
// userdata
HV_EXPORT void hloop_set_userdata(hloop_t* loop, void* userdata);
HV_EXPORT void* hloop_userdata(hloop_t* loop);
// custom_event
/*
* hevent_t ev;
* memset(&ev, 0, sizeof(hevent_t));
* ev.event_type = (hevent_type_e)(HEVENT_TYPE_CUSTOM + 1);
* ev.cb = custom_event_cb;
* ev.userdata = userdata;
* hloop_post_event(loop, &ev);
*/
// NOTE: hloop_post_event is thread-safe, used to post event from other thread to loop thread.
HV_EXPORT void hloop_post_event(hloop_t* loop, hevent_t* ev);
// idle
HV_EXPORT hidle_t* hidle_add(hloop_t* loop, hidle_cb cb, uint32_t repeat DEFAULT(INFINITE));
HV_EXPORT void hidle_del(hidle_t* idle);
// timer
// @param timeout: unit(ms)
HV_EXPORT htimer_t* htimer_add(hloop_t* loop, htimer_cb cb, uint32_t timeout, uint32_t repeat DEFAULT(INFINITE));
/*
* minute hour day week month cb
* 0~59 0~23 1~31 0~6 1~12
* -1 -1 -1 -1 -1 cron.minutely
* 30 -1 -1 -1 -1 cron.hourly
* 30 1 -1 -1 -1 cron.daily
* 30 1 15 -1 -1 cron.monthly
* 30 1 -1 5 -1 cron.weekly
* 30 1 1 -1 10 cron.yearly
*/
HV_EXPORT htimer_t* htimer_add_period(hloop_t* loop, htimer_cb cb,
int8_t minute DEFAULT(0), int8_t hour DEFAULT(-1), int8_t day DEFAULT(-1),
int8_t week DEFAULT(-1), int8_t month DEFAULT(-1), uint32_t repeat DEFAULT(INFINITE));
HV_EXPORT void htimer_del(htimer_t* timer);
HV_EXPORT void htimer_reset(htimer_t* timer);
// io
//-----------------------low-level apis---------------------------------------
#define HV_READ 0x0001
#define HV_WRITE 0x0004
#define HV_RDWR (HV_READ|HV_WRITE)
/*
const char* hio_engine() {
#ifdef EVENT_SELECT
return "select";
#elif defined(EVENT_POLL)
return "poll";
#elif defined(EVENT_EPOLL)
return "epoll";
#elif defined(EVENT_KQUEUE)
return "kqueue";
#elif defined(EVENT_IOCP)
return "iocp";
#elif defined(EVENT_PORT)
return "evport";
#else
return "noevent";
#endif
}
*/
HV_EXPORT const char* hio_engine();
HV_EXPORT hio_t* hio_get(hloop_t* loop, int fd);
HV_EXPORT int hio_add(hio_t* io, hio_cb cb, int events DEFAULT(HV_READ));
HV_EXPORT int hio_del(hio_t* io, int events DEFAULT(HV_RDWR));
// NOTE: io detach from old loop and attach to new loop
/* @see examples/multi-thread/one-acceptor-multi-workers.c
void new_conn_event(hevent_t* ev) {
hloop_t* loop = ev->loop;
hio_t* io = (hio_t*)hevent_userdata(ev);
hio_attach(loop, io);
}
void on_accpet(hio_t* io) {
hio_detach(io);
hloop_t* worker_loop = get_one_loop();
hevent_t ev;
memset(&ev, 0, sizeof(ev));
ev.loop = worker_loop;
ev.cb = new_conn_event;
ev.userdata = io;
hloop_post_event(worker_loop, &ev);
}
*/
HV_EXPORT void hio_detach(/*hloop_t* loop,*/ hio_t* io);
HV_EXPORT void hio_attach(hloop_t* loop, hio_t* io);
HV_EXPORT bool hio_exists(hloop_t* loop, int fd);
// hio_t fields
// NOTE: fd cannot be used as unique identifier, so we provide an id.
HV_EXPORT uint32_t hio_id (hio_t* io);
HV_EXPORT int hio_fd (hio_t* io);
HV_EXPORT int hio_error (hio_t* io);
HV_EXPORT int hio_events (hio_t* io);
HV_EXPORT int hio_revents (hio_t* io);
HV_EXPORT hio_type_e hio_type (hio_t* io);
HV_EXPORT struct sockaddr* hio_localaddr(hio_t* io);
HV_EXPORT struct sockaddr* hio_peeraddr (hio_t* io);
HV_EXPORT void hio_set_context(hio_t* io, void* ctx);
HV_EXPORT void* hio_context(hio_t* io);
HV_EXPORT bool hio_is_opened(hio_t* io);
HV_EXPORT bool hio_is_closed(hio_t* io);
// iobuf
// #include "hbuf.h"
typedef struct fifo_buf_s hio_readbuf_t;
// NOTE: One loop per thread, one readbuf per loop.
// But you can pass in your own readbuf instead of the default readbuf to avoid memcopy.
HV_EXPORT void hio_set_readbuf(hio_t* io, void* buf, size_t len);
HV_EXPORT hio_readbuf_t* hio_get_readbuf(hio_t* io);
HV_EXPORT void hio_set_max_read_bufsize (hio_t* io, uint32_t size);
HV_EXPORT void hio_set_max_write_bufsize(hio_t* io, uint32_t size);
// NOTE: hio_write is non-blocking, so there is a write queue inside hio_t to cache unwritten data and wait for writable.
// @return current buffer size of write queue.
HV_EXPORT size_t hio_write_bufsize(hio_t* io);
#define hio_write_is_complete(io) (hio_write_bufsize(io) == 0)
HV_EXPORT uint64_t hio_last_read_time(hio_t* io); // ms
HV_EXPORT uint64_t hio_last_write_time(hio_t* io); // ms
// set callbacks
HV_EXPORT void hio_setcb_accept (hio_t* io, haccept_cb accept_cb);
HV_EXPORT void hio_setcb_connect (hio_t* io, hconnect_cb connect_cb);
HV_EXPORT void hio_setcb_read (hio_t* io, hread_cb read_cb);
HV_EXPORT void hio_setcb_write (hio_t* io, hwrite_cb write_cb);
HV_EXPORT void hio_setcb_close (hio_t* io, hclose_cb close_cb);
// get callbacks
HV_EXPORT haccept_cb hio_getcb_accept(hio_t* io);
HV_EXPORT hconnect_cb hio_getcb_connect(hio_t* io);
HV_EXPORT hread_cb hio_getcb_read(hio_t* io);
HV_EXPORT hwrite_cb hio_getcb_write(hio_t* io);
HV_EXPORT hclose_cb hio_getcb_close(hio_t* io);
// Enable SSL/TLS is so easy :)
HV_EXPORT int hio_enable_ssl(hio_t* io);
HV_EXPORT bool hio_is_ssl(hio_t* io);
HV_EXPORT int hio_set_ssl (hio_t* io, hssl_t ssl);
HV_EXPORT int hio_set_ssl_ctx(hio_t* io, hssl_ctx_t ssl_ctx);
// hssl_ctx_new(opt) -> hio_set_ssl_ctx
HV_EXPORT int hio_new_ssl_ctx(hio_t* io, hssl_ctx_opt_t* opt);
HV_EXPORT hssl_t hio_get_ssl(hio_t* io);
HV_EXPORT hssl_ctx_t hio_get_ssl_ctx(hio_t* io);
// for hssl_set_sni_hostname
HV_EXPORT int hio_set_hostname(hio_t* io, const char* hostname);
HV_EXPORT const char* hio_get_hostname(hio_t* io);
// connect timeout => hclose_cb
HV_EXPORT void hio_set_connect_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_CONNECT_TIMEOUT));
// close timeout => hclose_cb
HV_EXPORT void hio_set_close_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_CLOSE_TIMEOUT));
// read timeout => hclose_cb
HV_EXPORT void hio_set_read_timeout(hio_t* io, int timeout_ms);
// write timeout => hclose_cb
HV_EXPORT void hio_set_write_timeout(hio_t* io, int timeout_ms);
// keepalive timeout => hclose_cb
HV_EXPORT void hio_set_keepalive_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_KEEPALIVE_TIMEOUT));
/*
void send_heartbeat(hio_t* io) {
static char buf[] = "PING\r\n";
hio_write(io, buf, 6);
}
hio_set_heartbeat(io, 3000, send_heartbeat);
*/
typedef void (*hio_send_heartbeat_fn)(hio_t* io);
// heartbeat interval => hio_send_heartbeat_fn
HV_EXPORT void hio_set_heartbeat(hio_t* io, int interval_ms, hio_send_heartbeat_fn fn);
// Nonblocking, poll IO events in the loop to call corresponding callback.
// hio_add(io, HV_READ) => accept => haccept_cb
HV_EXPORT int hio_accept (hio_t* io);
// connect => hio_add(io, HV_WRITE) => hconnect_cb
HV_EXPORT int hio_connect(hio_t* io);
// hio_add(io, HV_READ) => read => hread_cb
HV_EXPORT int hio_read (hio_t* io);
#define hio_read_start(io) hio_read(io)
#define hio_read_stop(io) hio_del(io, HV_READ)
// hio_read_start => hread_cb => hio_read_stop
HV_EXPORT int hio_read_once (hio_t* io);
// hio_read_once => hread_cb(len)
HV_EXPORT int hio_read_until_length(hio_t* io, unsigned int len);
// hio_read_once => hread_cb(...delim)
HV_EXPORT int hio_read_until_delim (hio_t* io, unsigned char delim);
HV_EXPORT int hio_read_remain(hio_t* io);
// @see examples/tinyhttpd.c examples/tinyproxyd.c
#define hio_readline(io) hio_read_until_delim(io, '\n')
#define hio_readstring(io) hio_read_until_delim(io, '\0')
#define hio_readbytes(io, len) hio_read_until_length(io, len)
#define hio_read_until(io, len) hio_read_until_length(io, len)
// NOTE: hio_write is thread-safe, locked by recursive_mutex, allow to be called by other threads.
// hio_try_write => hio_add(io, HV_WRITE) => write => hwrite_cb
HV_EXPORT int hio_write (hio_t* io, const void* buf, size_t len);
// NOTE: hio_close is thread-safe, hio_close_async will be called actually in other thread.
// hio_del(io, HV_RDWR) => close => hclose_cb
HV_EXPORT int hio_close (hio_t* io);
// NOTE: hloop_post_event(hio_close_event)
HV_EXPORT int hio_close_async(hio_t* io);
//------------------high-level apis-------------------------------------------
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
HV_EXPORT hio_t* hread (hloop_t* loop, int fd, void* buf, size_t len, hread_cb read_cb);
// hio_get -> hio_setcb_write -> hio_write
HV_EXPORT hio_t* hwrite (hloop_t* loop, int fd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
// hio_get -> hio_close
HV_EXPORT void hclose (hloop_t* loop, int fd);
// tcp
// hio_get -> hio_setcb_accept -> hio_accept
HV_EXPORT hio_t* haccept (hloop_t* loop, int listenfd, haccept_cb accept_cb);
// hio_get -> hio_setcb_connect -> hio_connect
HV_EXPORT hio_t* hconnect (hloop_t* loop, int connfd, hconnect_cb connect_cb);
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
HV_EXPORT hio_t* hrecv (hloop_t* loop, int connfd, void* buf, size_t len, hread_cb read_cb);
// hio_get -> hio_setcb_write -> hio_write
HV_EXPORT hio_t* hsend (hloop_t* loop, int connfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
// udp
HV_EXPORT void hio_set_type(hio_t* io, hio_type_e type);
HV_EXPORT void hio_set_localaddr(hio_t* io, struct sockaddr* addr, int addrlen);
HV_EXPORT void hio_set_peeraddr (hio_t* io, struct sockaddr* addr, int addrlen);
// NOTE: must call hio_set_peeraddr before hrecvfrom/hsendto
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
HV_EXPORT hio_t* hrecvfrom (hloop_t* loop, int sockfd, void* buf, size_t len, hread_cb read_cb);
// hio_get -> hio_setcb_write -> hio_write
HV_EXPORT hio_t* hsendto (hloop_t* loop, int sockfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
//-----------------top-level apis---------------------------------------------
// @hio_create_socket: socket -> bind -> listen
// sockaddr_set_ipport -> socket -> hio_get(loop, sockfd) ->
// side == HIO_SERVER_SIDE ? bind ->
// type & HIO_TYPE_SOCK_STREAM ? listen ->
HV_EXPORT hio_t* hio_create_socket(hloop_t* loop, const char* host, int port,
hio_type_e type DEFAULT(HIO_TYPE_TCP),
hio_side_e side DEFAULT(HIO_SERVER_SIDE));
// @tcp_server: hio_create_socket(loop, host, port, HIO_TYPE_TCP, HIO_SERVER_SIDE) -> hio_setcb_accept -> hio_accept
// @see examples/tcp_echo_server.c
HV_EXPORT hio_t* hloop_create_tcp_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb);
// @tcp_client: hio_create_socket(loop, host, port, HIO_TYPE_TCP, HIO_CLIENT_SIDE) -> hio_setcb_connect -> hio_setcb_close -> hio_connect
// @see examples/nc.c
HV_EXPORT hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb, hclose_cb close_cb);
// @ssl_server: hio_create_socket(loop, host, port, HIO_TYPE_SSL, HIO_SERVER_SIDE) -> hio_setcb_accept -> hio_accept
// @see examples/tcp_echo_server.c => #define TEST_SSL 1
HV_EXPORT hio_t* hloop_create_ssl_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb);
// @ssl_client: hio_create_socket(loop, host, port, HIO_TYPE_SSL, HIO_CLIENT_SIDE) -> hio_setcb_connect -> hio_setcb_close -> hio_connect
// @see examples/nc.c => #define TEST_SSL 1
HV_EXPORT hio_t* hloop_create_ssl_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb, hclose_cb close_cb);
// @udp_server: hio_create_socket(loop, host, port, HIO_TYPE_UDP, HIO_SERVER_SIDE)
// @see examples/udp_echo_server.c
HV_EXPORT hio_t* hloop_create_udp_server (hloop_t* loop, const char* host, int port);
// @udp_server: hio_create_socket(loop, host, port, HIO_TYPE_UDP, HIO_CLIENT_SIDE)
// @see examples/nc.c
HV_EXPORT hio_t* hloop_create_udp_client (hloop_t* loop, const char* host, int port);
//-----------------upstream---------------------------------------------
// hio_read(io)
// hio_read(io->upstream_io)
HV_EXPORT void hio_read_upstream(hio_t* io);
// hio_write(io->upstream_io, buf, bytes)
HV_EXPORT void hio_write_upstream(hio_t* io, void* buf, int bytes);
// hio_close(io->upstream_io)
HV_EXPORT void hio_close_upstream(hio_t* io);
// io1->upstream_io = io2;
// io2->upstream_io = io1;
// @see examples/socks5_proxy_server.c
HV_EXPORT void hio_setup_upstream(hio_t* io1, hio_t* io2);
// @return io->upstream_io
HV_EXPORT hio_t* hio_get_upstream(hio_t* io);
// @tcp_upstream: hio_create_socket -> hio_setup_upstream -> hio_connect -> on_connect -> hio_read_upstream
// @return upstream_io
// @see examples/tcp_proxy_server.c
HV_EXPORT hio_t* hio_setup_tcp_upstream(hio_t* io, const char* host, int port, int ssl DEFAULT(0));
#define hio_setup_ssl_upstream(io, host, port) hio_setup_tcp_upstream(io, host, port, 1)
// @udp_upstream: hio_create_socket -> hio_setup_upstream -> hio_read_upstream
// @return upstream_io
// @see examples/udp_proxy_server.c
HV_EXPORT hio_t* hio_setup_udp_upstream(hio_t* io, const char* host, int port);
//-----------------unpack---------------------------------------------
typedef enum {
UNPACK_MODE_NONE = 0,
UNPACK_BY_FIXED_LENGTH = 1, // Not recommended
UNPACK_BY_DELIMITER = 2, // Suitable for text protocol
UNPACK_BY_LENGTH_FIELD = 3, // Suitable for binary protocol
} unpack_mode_e;
#define DEFAULT_PACKAGE_MAX_LENGTH (1 << 21) // 2M
// UNPACK_BY_DELIMITER
#define PACKAGE_MAX_DELIMITER_BYTES 8
// UNPACK_BY_LENGTH_FIELD
typedef enum {
ENCODE_BY_VARINT = 17, // 1 MSB + 7 bits
ENCODE_BY_LITTEL_ENDIAN = LITTLE_ENDIAN, // 1234
ENCODE_BY_BIG_ENDIAN = BIG_ENDIAN, // 4321
} unpack_coding_e;
typedef struct unpack_setting_s {
unpack_mode_e mode;
unsigned int package_max_length;
union {
// UNPACK_BY_FIXED_LENGTH
struct {
unsigned int fixed_length;
};
// UNPACK_BY_DELIMITER
struct {
unsigned char delimiter[PACKAGE_MAX_DELIMITER_BYTES];
unsigned short delimiter_bytes;
};
// UNPACK_BY_LENGTH_FIELD
/* package_len = head_len + body_len + length_adjustment
*
* if (length_field_coding == ENCODE_BY_VARINT) head_len = body_offset + varint_bytes - length_field_bytes;
* else head_len = body_offset;
*
* body_len calc by length_field
*
*/
struct {
unsigned short body_offset;
unsigned short length_field_offset;
unsigned short length_field_bytes;
short length_adjustment;
unpack_coding_e length_field_coding;
};
};
#ifdef __cplusplus
unpack_setting_s() {
// Recommended setting:
// head = flags:1byte + length:4bytes = 5bytes
mode = UNPACK_BY_LENGTH_FIELD;
package_max_length = DEFAULT_PACKAGE_MAX_LENGTH;
fixed_length = 0;
delimiter_bytes = 0;
body_offset = 5;
length_field_offset = 1;
length_field_bytes = 4;
length_field_coding = ENCODE_BY_BIG_ENDIAN;
length_adjustment = 0;
}
#endif
} unpack_setting_t;
// @see examples/jsonrpc examples/protorpc
HV_EXPORT void hio_set_unpack(hio_t* io, unpack_setting_t* setting);
HV_EXPORT void hio_unset_unpack(hio_t* io);
// unpack examples
/*
unpack_setting_t ftp_unpack_setting;
memset(&ftp_unpack_setting, 0, sizeof(unpack_setting_t));
ftp_unpack_setting.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH;
ftp_unpack_setting.mode = UNPACK_BY_DELIMITER;
ftp_unpack_setting.delimiter[0] = '\r';
ftp_unpack_setting.delimiter[1] = '\n';
ftp_unpack_setting.delimiter_bytes = 2;
unpack_setting_t mqtt_unpack_setting = {
.mode = UNPACK_BY_LENGTH_FIELD,
.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH,
.body_offset = 2,
.length_field_offset = 1,
.length_field_bytes = 1,
.length_field_coding = ENCODE_BY_VARINT,
};
unpack_setting_t grpc_unpack_setting = {
.mode = UNPACK_BY_LENGTH_FIELD,
.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH,
.body_offset = 5,
.length_field_offset = 1,
.length_field_bytes = 4,
.length_field_coding = ENCODE_BY_BIG_ENDIAN,
};
*/
//-----------------reconnect----------------------------------------
#define DEFAULT_RECONNECT_MIN_DELAY 1000 // ms
#define DEFAULT_RECONNECT_MAX_DELAY 60000 // ms
#define DEFAULT_RECONNECT_DELAY_POLICY 2 // exponential
#define DEFAULT_RECONNECT_MAX_RETRY_CNT INFINITE
typedef struct reconn_setting_s {
uint32_t min_delay; // ms
uint32_t max_delay; // ms
uint32_t cur_delay; // ms
/*
* @delay_policy
* 0: fixed
* min_delay=3s => 3,3,3...
* 1: linear
* min_delay=3s max_delay=10s => 3,6,9,10,10...
* other: exponential
* min_delay=3s max_delay=60s delay_policy=2 => 3,6,12,24,48,60,60...
*/
uint32_t delay_policy;
uint32_t max_retry_cnt;
uint32_t cur_retry_cnt;
#ifdef __cplusplus
reconn_setting_s() {
min_delay = DEFAULT_RECONNECT_MIN_DELAY;
max_delay = DEFAULT_RECONNECT_MAX_DELAY;
cur_delay = 0;
// 1,2,4,8,16,32,60,60...
delay_policy = DEFAULT_RECONNECT_DELAY_POLICY;
max_retry_cnt = DEFAULT_RECONNECT_MAX_RETRY_CNT;
cur_retry_cnt = 0;
}
#endif
} reconn_setting_t;
HV_INLINE void reconn_setting_init(reconn_setting_t* reconn) {
reconn->min_delay = DEFAULT_RECONNECT_MIN_DELAY;
reconn->max_delay = DEFAULT_RECONNECT_MAX_DELAY;
reconn->cur_delay = 0;
// 1,2,4,8,16,32,60,60...
reconn->delay_policy = DEFAULT_RECONNECT_DELAY_POLICY;
reconn->max_retry_cnt = DEFAULT_RECONNECT_MAX_RETRY_CNT;
reconn->cur_retry_cnt = 0;
}
HV_INLINE void reconn_setting_reset(reconn_setting_t* reconn) {
reconn->cur_delay = 0;
reconn->cur_retry_cnt = 0;
}
HV_INLINE bool reconn_setting_can_retry(reconn_setting_t* reconn) {
++reconn->cur_retry_cnt;
return reconn->max_retry_cnt == INFINITE ||
reconn->cur_retry_cnt < reconn->max_retry_cnt;
}
HV_INLINE uint32_t reconn_setting_calc_delay(reconn_setting_t* reconn) {
if (reconn->delay_policy == 0) {
// fixed
reconn->cur_delay = reconn->min_delay;
} else if (reconn->delay_policy == 1) {
// linear
reconn->cur_delay += reconn->min_delay;
} else {
// exponential
reconn->cur_delay *= reconn->delay_policy;
}
reconn->cur_delay = MAX(reconn->cur_delay, reconn->min_delay);
reconn->cur_delay = MIN(reconn->cur_delay, reconn->max_delay);
return reconn->cur_delay;
}
//-----------------LoadBalance-------------------------------------
typedef enum {
LB_RoundRobin,
LB_Random,
LB_LeastConnections,
LB_IpHash,
LB_UrlHash,
} load_balance_e;
//-----------------rudp---------------------------------------------
#if WITH_KCP
#define WITH_RUDP 1
#endif
#if WITH_RUDP
// NOTE: hio_close_rudp is thread-safe.
HV_EXPORT int hio_close_rudp(hio_t* io, struct sockaddr* peeraddr DEFAULT(NULL));
#endif
#if WITH_KCP
typedef struct kcp_setting_s {
// ikcp_create(conv, ...)
unsigned int conv;
// ikcp_nodelay(kcp, nodelay, interval, fastresend, nocwnd)
int nodelay;
int interval;
int fastresend;
int nocwnd;
// ikcp_wndsize(kcp, sndwnd, rcvwnd)
int sndwnd;
int rcvwnd;
// ikcp_setmtu(kcp, mtu)
int mtu;
// ikcp_update
int update_interval;
#ifdef __cplusplus
kcp_setting_s() {
conv = 0x11223344;
// normal mode
nodelay = 0;
interval = 40;
fastresend = 0;
nocwnd = 0;
// fast mode
// nodelay = 1;
// interval = 10;
// fastresend = 2;
// nocwnd = 1;
sndwnd = 0;
rcvwnd = 0;
mtu = 1400;
update_interval = 10; // ms
}
#endif
} kcp_setting_t;
// @see examples/udp_echo_server.c => #define TEST_KCP 1
HV_EXPORT int hio_set_kcp(hio_t* io, kcp_setting_t* setting DEFAULT(NULL));
#endif
END_EXTERN_C
#endif // HV_LOOP_H_

View File

@ -0,0 +1,117 @@
#ifndef HV_MAIN_H_
#define HV_MAIN_H_
#include "hexport.h"
#include "hplatform.h"
#include "hdef.h"
#include "hproc.h"
#ifdef _MSC_VER
#pragma comment(lib, "winmm.lib") // for timeSetEvent
#endif
BEGIN_EXTERN_C
typedef struct main_ctx_s {
char run_dir[MAX_PATH];
char program_name[MAX_PATH];
char confile[MAX_PATH]; // default etc/${program}.conf
char pidfile[MAX_PATH]; // default logs/${program}.pid
char logfile[MAX_PATH]; // default logs/${program}.log
pid_t pid; // getpid
pid_t oldpid; // getpid_from_pidfile
// arg
int argc;
int arg_len;
char** os_argv;
char** save_argv;
char* cmdline;
// parsed arg
int arg_kv_size;
char** arg_kv;
int arg_list_size;
char** arg_list;
// env
int envc;
int env_len;
char** os_envp;
char** save_envp;
// signals
procedure_t reload_fn;
void* reload_userdata;
// master workers model
int worker_processes;
int worker_threads;
procedure_t worker_fn;
void* worker_userdata;
proc_ctx_t* proc_ctxs;
} main_ctx_t;
// arg_type
#define NO_ARGUMENT 0
#define REQUIRED_ARGUMENT 1
#define OPTIONAL_ARGUMENT 2
// option define
#define OPTION_PREFIX '-'
#define OPTION_DELIM '='
#define OPTION_ENABLE "1"
#define OPTION_DISABLE "0"
typedef struct option_s {
char short_opt;
const char* long_opt;
int arg_type;
} option_t;
HV_EXPORT int main_ctx_init(int argc, char** argv);
HV_EXPORT void main_ctx_free();
// ls -a -l
// ls -al
// watch -n 10 ls
// watch -n10 ls
HV_EXPORT int parse_opt(int argc, char** argv, const char* opt);
// gcc -g -Wall -O3 -std=cpp main.c
HV_EXPORT int parse_opt_long(int argc, char** argv, const option_t* long_options, int size);
HV_EXPORT const char* get_arg(const char* key);
HV_EXPORT const char* get_env(const char* key);
#if defined(OS_UNIX) && !HAVE_SETPROCTITLE
HV_EXPORT void setproctitle(const char* fmt, ...);
#endif
// pidfile
HV_EXPORT int create_pidfile();
HV_EXPORT void delete_pidfile();
HV_EXPORT pid_t getpid_from_pidfile();
// signal=[start,stop,restart,status,reload]
HV_EXPORT int signal_init(procedure_t reload_fn DEFAULT(NULL), void* reload_userdata DEFAULT(NULL));
HV_EXPORT void signal_handle(const char* signal);
#ifdef OS_UNIX
// we use SIGTERM to quit process, SIGUSR1 to reload confile
#define SIGNAL_TERMINATE SIGTERM
#define SIGNAL_RELOAD SIGUSR1
void signal_handler(int signo);
#endif
// global var
#define DEFAULT_WORKER_PROCESSES 4
#define MAXNUM_WORKER_PROCESSES 256
HV_EXPORT extern main_ctx_t g_main_ctx;
// master-workers processes
HV_EXPORT int master_workers_run(
procedure_t worker_fn,
void* worker_userdata DEFAULT(NULL),
int worker_processes DEFAULT(DEFAULT_WORKER_PROCESSES),
int worker_threads DEFAULT(0),
bool wait DEFAULT(true));
END_EXTERN_C
#endif // HV_MAIN_H_

View File

@ -0,0 +1,56 @@
#ifndef HV_MAP_H_
#define HV_MAP_H_
#include "hconfig.h"
#include <map>
#include <string>
// MultiMap
namespace std {
/*
int main() {
std::MultiMap<std::string, std::string> kvs;
kvs["name"] = "hw";
kvs["filename"] = "1.jpg";
kvs["filename"] = "2.jpg";
//kvs.insert(std::pair<std::string,std::string>("name", "hw"));
//kvs.insert(std::pair<std::string,std::string>("filename", "1.jpg"));
//kvs.insert(std::pair<std::string,std::string>("filename", "2.jpg"));
for (auto& pair : kvs) {
printf("%s:%s\n", pair.first.c_str(), pair.second.c_str());
}
auto iter = kvs.find("filename");
if (iter != kvs.end()) {
for (int i = 0; i < kvs.count("filename"); ++i, ++iter) {
printf("%s:%s\n", iter->first.c_str(), iter->second.c_str());
}
}
return 0;
}
*/
template<typename Key,typename Value>
class MultiMap : public multimap<Key, Value> {
public:
Value& operator[](Key key) {
auto iter = this->insert(std::pair<Key,Value>(key,Value()));
return (*iter).second;
}
};
}
#ifdef USE_MULTIMAP
#define HV_MAP std::MultiMap
#else
#define HV_MAP std::map
#endif
// KeyValue
typedef std::map<std::string, std::string> keyval_t;
typedef std::MultiMap<std::string, std::string> multi_keyval_t;
namespace hv {
typedef HV_MAP<std::string, std::string> KeyValue;
}
#endif // HV_MAP_H_

View File

@ -0,0 +1,68 @@
#ifndef HV_MATH_H_
#define HV_MATH_H_
#include <math.h>
static inline unsigned long floor2e(unsigned long num) {
unsigned long n = num;
int e = 0;
while (n>>=1) ++e;
unsigned long ret = 1;
while (e--) ret<<=1;
return ret;
}
static inline unsigned long ceil2e(unsigned long num) {
// 2**0 = 1
if (num == 0 || num == 1) return 1;
unsigned long n = num - 1;
int e = 1;
while (n>>=1) ++e;
unsigned long ret = 1;
while (e--) ret<<=1;
return ret;
}
// varint little-endian
// MSB
static inline int varint_encode(long long value, unsigned char* buf) {
unsigned char ch;
unsigned char *p = buf;
int bytes = 0;
do {
ch = value & 0x7F;
value >>= 7;
*p++ = value == 0 ? ch : (ch | 0x80);
++bytes;
} while (value);
return bytes;
}
// @param[IN|OUT] len: in=>buflen, out=>varint bytesize
static inline long long varint_decode(const unsigned char* buf, int* len) {
long long ret = 0;
int bytes = 0, bits = 0;
const unsigned char *p = buf;
do {
if (len && *len && bytes == *len) {
// Not enough length
*len = 0;
return 0;
}
ret |= ((long long)(*p & 0x7F)) << bits;
++bytes;
if ((*p & 0x80) == 0) {
// Found end
if (len) *len = bytes;
return ret;
}
++p;
bits += 7;
} while(bytes < 10);
// Not found end
if (len) *len = -1;
return ret;
}
#endif // HV_MATH_H_

View File

@ -0,0 +1,268 @@
#ifndef HV_MUTEX_H_
#define HV_MUTEX_H_
#include "hexport.h"
#include "hplatform.h"
#include "htime.h"
BEGIN_EXTERN_C
#ifdef _MSC_VER
#define hmutex_t CRITICAL_SECTION
#define hmutex_init InitializeCriticalSection
#define hmutex_destroy DeleteCriticalSection
#define hmutex_lock EnterCriticalSection
#define hmutex_unlock LeaveCriticalSection
#define hrecursive_mutex_t CRITICAL_SECTION
#define hrecursive_mutex_init InitializeCriticalSection
#define hrecursive_mutex_destroy DeleteCriticalSection
#define hrecursive_mutex_lock EnterCriticalSection
#define hrecursive_mutex_unlock LeaveCriticalSection
#define HSPINLOCK_COUNT -1
#define hspinlock_t CRITICAL_SECTION
#define hspinlock_init(pspin) InitializeCriticalSectionAndSpinCount(pspin, HSPINLOCK_COUNT)
#define hspinlock_destroy DeleteCriticalSection
#define hspinlock_lock EnterCriticalSection
#define hspinlock_unlock LeaveCriticalSection
#define hrwlock_t SRWLOCK
#define hrwlock_init InitializeSRWLock
#define hrwlock_destroy(plock)
#define hrwlock_rdlock AcquireSRWLockShared
#define hrwlock_rdunlock ReleaseSRWLockShared
#define hrwlock_wrlock AcquireSRWLockExclusive
#define hrwlock_wrunlock ReleaseSRWLockExclusive
#define htimed_mutex_t HANDLE
#define htimed_mutex_init(pmutex) *(pmutex) = CreateMutex(NULL, FALSE, NULL)
#define htimed_mutex_destroy(pmutex) CloseHandle(*(pmutex))
#define htimed_mutex_lock(pmutex) WaitForSingleObject(*(pmutex), INFINITE)
#define htimed_mutex_unlock(pmutex) ReleaseMutex(*(pmutex))
// true: WAIT_OBJECT_0
// false: WAIT_OBJECT_TIMEOUT
#define htimed_mutex_lock_for(pmutex, ms) ( WaitForSingleObject(*(pmutex), ms) == WAIT_OBJECT_0 )
#define hcondvar_t CONDITION_VARIABLE
#define hcondvar_init InitializeConditionVariable
#define hcondvar_destroy(pcond)
#define hcondvar_wait(pcond, pmutex) SleepConditionVariableCS(pcond, pmutex, INFINITE)
#define hcondvar_wait_for(pcond, pmutex, ms) SleepConditionVariableCS(pcond, pmutex, ms)
#define hcondvar_signal WakeConditionVariable
#define hcondvar_broadcast WakeAllConditionVariable
#define honce_t INIT_ONCE
#define HONCE_INIT INIT_ONCE_STATIC_INIT
typedef void (*honce_fn)();
static inline BOOL WINAPI s_once_func(INIT_ONCE* once, PVOID arg, PVOID* _) {
honce_fn fn = (honce_fn)arg;
fn();
return TRUE;
}
static inline void honce(honce_t* once, honce_fn fn) {
PVOID dummy = NULL;
InitOnceExecuteOnce(once, s_once_func, (PVOID)fn, &dummy);
}
#define hsem_t HANDLE
#define hsem_init(psem, value) *(psem) = CreateSemaphore(NULL, value, value+100000, NULL)
#define hsem_destroy(psem) CloseHandle(*(psem))
#define hsem_wait(psem) WaitForSingleObject(*(psem), INFINITE)
#define hsem_post(psem) ReleaseSemaphore(*(psem), 1, NULL)
// true: WAIT_OBJECT_0
// false: WAIT_OBJECT_TIMEOUT
#define hsem_wait_for(psem, ms) ( WaitForSingleObject(*(psem), ms) == WAIT_OBJECT_0 )
#else
#define hmutex_t pthread_mutex_t
#define hmutex_init(pmutex) pthread_mutex_init(pmutex, NULL)
#define hmutex_destroy pthread_mutex_destroy
#define hmutex_lock pthread_mutex_lock
#define hmutex_unlock pthread_mutex_unlock
#define hrecursive_mutex_t pthread_mutex_t
#define hrecursive_mutex_init(pmutex) \
do {\
pthread_mutexattr_t attr;\
pthread_mutexattr_init(&attr);\
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\
pthread_mutex_init(pmutex, &attr);\
} while(0)
#define hrecursive_mutex_destroy pthread_mutex_destroy
#define hrecursive_mutex_lock pthread_mutex_lock
#define hrecursive_mutex_unlock pthread_mutex_unlock
#if HAVE_PTHREAD_SPIN_LOCK
#define hspinlock_t pthread_spinlock_t
#define hspinlock_init(pspin) pthread_spin_init(pspin, PTHREAD_PROCESS_PRIVATE)
#define hspinlock_destroy pthread_spin_destroy
#define hspinlock_lock pthread_spin_lock
#define hspinlock_unlock pthread_spin_unlock
#else
#define hspinlock_t pthread_mutex_t
#define hspinlock_init(pmutex) pthread_mutex_init(pmutex, NULL)
#define hspinlock_destroy pthread_mutex_destroy
#define hspinlock_lock pthread_mutex_lock
#define hspinlock_unlock pthread_mutex_unlock
#endif
#define hrwlock_t pthread_rwlock_t
#define hrwlock_init(prwlock) pthread_rwlock_init(prwlock, NULL)
#define hrwlock_destroy pthread_rwlock_destroy
#define hrwlock_rdlock pthread_rwlock_rdlock
#define hrwlock_rdunlock pthread_rwlock_unlock
#define hrwlock_wrlock pthread_rwlock_wrlock
#define hrwlock_wrunlock pthread_rwlock_unlock
#define htimed_mutex_t pthread_mutex_t
#define htimed_mutex_init(pmutex) pthread_mutex_init(pmutex, NULL)
#define htimed_mutex_destroy pthread_mutex_destroy
#define htimed_mutex_lock pthread_mutex_lock
#define htimed_mutex_unlock pthread_mutex_unlock
static inline void timespec_after(struct timespec* ts, unsigned int ms) {
struct timeval tv;
gettimeofday(&tv, NULL);
ts->tv_sec = tv.tv_sec + ms / 1000;
ts->tv_nsec = tv.tv_usec * 1000 + ms % 1000 * 1000000;
if (ts->tv_nsec >= 1000000000) {
ts->tv_nsec -= 1000000000;
ts->tv_sec += 1;
}
}
// true: OK
// false: ETIMEDOUT
static inline int htimed_mutex_lock_for(htimed_mutex_t* mutex, unsigned int ms) {
#if HAVE_PTHREAD_MUTEX_TIMEDLOCK
struct timespec ts;
timespec_after(&ts, ms);
return pthread_mutex_timedlock(mutex, &ts) != ETIMEDOUT;
#else
int ret = 0;
unsigned int end = gettick_ms() + ms;
while ((ret = pthread_mutex_trylock(mutex)) != 0) {
if (gettick_ms() >= end) {
break;
}
hv_msleep(1);
}
return ret == 0;
#endif
}
#define hcondvar_t pthread_cond_t
#define hcondvar_init(pcond) pthread_cond_init(pcond, NULL)
#define hcondvar_destroy pthread_cond_destroy
#define hcondvar_wait pthread_cond_wait
#define hcondvar_signal pthread_cond_signal
#define hcondvar_broadcast pthread_cond_broadcast
// true: OK
// false: ETIMEDOUT
static inline int hcondvar_wait_for(hcondvar_t* cond, hmutex_t* mutex, unsigned int ms) {
struct timespec ts;
timespec_after(&ts, ms);
return pthread_cond_timedwait(cond, mutex, &ts) != ETIMEDOUT;
}
#define honce_t pthread_once_t
#define HONCE_INIT PTHREAD_ONCE_INIT
#define honce pthread_once
#include <semaphore.h>
#define hsem_t sem_t
#define hsem_init(psem, value) sem_init(psem, 0, value)
#define hsem_destroy sem_destroy
#define hsem_wait sem_wait
#define hsem_post sem_post
// true: OK
// false: ETIMEDOUT
static inline int hsem_wait_for(hsem_t* sem, unsigned int ms) {
#if HAVE_SEM_TIMEDWAIT
struct timespec ts;
timespec_after(&ts, ms);
return sem_timedwait(sem, &ts) != ETIMEDOUT;
#else
int ret = 0;
unsigned int end = gettick_ms() + ms;
while ((ret = sem_trywait(sem)) != 0) {
if (gettick_ms() >= end) {
break;
}
hv_msleep(1);
}
return ret == 0;
#endif
}
#endif
END_EXTERN_C
#ifdef __cplusplus
#include <mutex>
#include <condition_variable>
// using std::mutex;
// NOTE: test std::timed_mutex incorrect in some platforms, use htimed_mutex_t
// using std::timed_mutex;
using std::condition_variable;
using std::lock_guard;
using std::unique_lock;
BEGIN_NAMESPACE_HV
class MutexLock {
public:
MutexLock() { hmutex_init(&_mutex); }
~MutexLock() { hmutex_destroy(&_mutex); }
void lock() { hmutex_lock(&_mutex); }
void unlock() { hmutex_unlock(&_mutex); }
protected:
hmutex_t _mutex;
};
class SpinLock {
public:
SpinLock() { hspinlock_init(&_spin); }
~SpinLock() { hspinlock_destroy(&_spin); }
void lock() { hspinlock_lock(&_spin); }
void unlock() { hspinlock_unlock(&_spin); }
protected:
hspinlock_t _spin;
};
class RWLock {
public:
RWLock() { hrwlock_init(&_rwlock); }
~RWLock() { hrwlock_destroy(&_rwlock); }
void rdlock() { hrwlock_rdlock(&_rwlock); }
void rdunlock() { hrwlock_rdunlock(&_rwlock); }
void wrlock() { hrwlock_wrlock(&_rwlock); }
void wrunlock() { hrwlock_wrunlock(&_rwlock); }
void lock() { rdlock(); }
void unlock() { rdunlock(); }
protected:
hrwlock_t _rwlock;
};
template<class T>
class LockGuard {
public:
LockGuard(T& t) : _lock(t) { _lock.lock(); }
~LockGuard() { _lock.unlock(); }
protected:
T& _lock;
};
END_NAMESPACE_HV
// same as java synchronized(lock) { ... }
#define synchronized(lock) for (std::lock_guard<std::mutex> _lock_(lock), *p = &_lock_; p != NULL; p = NULL)
#endif // __cplusplus
#endif // HV_MUTEX_H_

View File

@ -0,0 +1,179 @@
#ifndef HV_OBJECT_POOL_H_
#define HV_OBJECT_POOL_H_
#include <list>
#include <memory>
#include <mutex>
#include <condition_variable>
#define DEFAULT_OBJECT_POOL_INIT_NUM 0
#define DEFAULT_OBJECT_POOL_MAX_NUM 4
#define DEFAULT_OBJECT_POOL_TIMEOUT 3000 // ms
template<class T>
class HObjectFactory {
public:
static T* create() {
return new T;
}
};
template<class T, class TFactory = HObjectFactory<T>>
class HObjectPool {
public:
HObjectPool(
int init_num = DEFAULT_OBJECT_POOL_INIT_NUM,
int max_num = DEFAULT_OBJECT_POOL_MAX_NUM,
int timeout = DEFAULT_OBJECT_POOL_TIMEOUT)
: _max_num(max_num)
, _timeout(timeout)
{
for (int i = 0; i < init_num; ++i) {
T* p = TFactory::create();
if (p) {
objects_.push_back(std::shared_ptr<T>(p));
}
}
_object_num = objects_.size();
}
~HObjectPool() {}
int ObjectNum() { return _object_num; }
int IdleNum() { return objects_.size(); }
int BorrowNum() { return ObjectNum() - IdleNum(); }
std::shared_ptr<T> TryBorrow() {
std::shared_ptr<T> pObj = NULL;
std::lock_guard<std::mutex> locker(mutex_);
if (!objects_.empty()) {
pObj = objects_.front();
objects_.pop_front();
}
return pObj;
}
std::shared_ptr<T> Borrow() {
std::shared_ptr<T> pObj = TryBorrow();
if (pObj) {
return pObj;
}
std::unique_lock<std::mutex> locker(mutex_);
if (_object_num < _max_num) {
++_object_num;
// NOTE: unlock to avoid TFactory::create block
mutex_.unlock();
T* p = TFactory::create();
mutex_.lock();
if (!p) --_object_num;
return std::shared_ptr<T>(p);
}
if (_timeout > 0) {
std::cv_status status = cond_.wait_for(locker, std::chrono::milliseconds(_timeout));
if (status == std::cv_status::timeout) {
return NULL;
}
if (!objects_.empty()) {
pObj = objects_.front();
objects_.pop_front();
return pObj;
}
else {
// WARN: No idle object
}
}
return pObj;
}
void Return(std::shared_ptr<T>& pObj) {
if (!pObj) return;
std::lock_guard<std::mutex> locker(mutex_);
objects_.push_back(pObj);
cond_.notify_one();
}
bool Add(std::shared_ptr<T>& pObj) {
std::lock_guard<std::mutex> locker(mutex_);
if (_object_num >= _max_num) {
return false;
}
objects_.push_back(pObj);
++_object_num;
cond_.notify_one();
return true;
}
bool Remove(std::shared_ptr<T>& pObj) {
std::lock_guard<std::mutex> locker(mutex_);
auto iter = objects_.begin();
while (iter != objects_.end()) {
if (*iter == pObj) {
iter = objects_.erase(iter);
--_object_num;
return true;
}
else {
++iter;
}
}
return false;
}
void Clear() {
std::lock_guard<std::mutex> locker(mutex_);
objects_.clear();
_object_num = 0;
}
int _object_num;
int _max_num;
int _timeout;
private:
std::list<std::shared_ptr<T>> objects_;
std::mutex mutex_;
std::condition_variable cond_;
};
template<class T, class TFactory = HObjectFactory<T>>
class HPoolObject {
public:
typedef HObjectPool<T, TFactory> PoolType;
HPoolObject(PoolType& pool) : pool_(pool)
{
sptr_ = pool_.Borrow();
}
~HPoolObject() {
if (sptr_) {
pool_.Return(sptr_);
}
}
HPoolObject(const HPoolObject<T>&) = delete;
HPoolObject<T>& operator=(const HPoolObject<T>&) = delete;
T* get() {
return sptr_.get();
}
operator bool() {
return sptr_.get() != NULL;
}
T* operator->() {
return sptr_.get();
}
T operator*() {
return *sptr_.get();
}
private:
PoolType& pool_;
std::shared_ptr<T> sptr_;
};
#endif // HV_OBJECT_POOL_H_

View File

@ -0,0 +1,28 @@
#ifndef HV_PATH_H_
#define HV_PATH_H_
#include <string> // for std::string
#include "hexport.h"
class HV_EXPORT HPath {
public:
static bool exists(const char* path);
static bool isdir(const char* path);
static bool isfile(const char* path);
static bool islink(const char* path);
// filepath = /mnt/share/image/test.jpg
// basename = test.jpg
// dirname = /mnt/share/image
// filename = test
// suffixname = jpg
static std::string basename(const std::string& filepath);
static std::string dirname(const std::string& filepath);
static std::string filename(const std::string& filepath);
static std::string suffixname(const std::string& filepath);
static std::string join(const std::string& dir, const std::string& filename);
};
#endif // HV_PATH_H_

Some files were not shown because too many files have changed in this diff Show More