main
parent
a386d0c62b
commit
6dd317d14d
|
@ -0,0 +1,3 @@
|
||||||
|
/3rdPartner/frp_0.56.0_linux_arm.tar.gz
|
||||||
|
/3rdPartner/go1.22.1.linux-armv6l.tar.gz
|
||||||
|
/appRelease/test.release
|
|
@ -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_ */
|
|
@ -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();
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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));
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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());
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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() << "\"";
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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 << ' ';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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 << '>';
|
||||||
|
}
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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() << '>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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);
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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";
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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()
|
||||||
|
{}
|
|
@ -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_ */
|
|
@ -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()
|
||||||
|
{}
|
|
@ -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_ */
|
|
@ -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()
|
||||||
|
{}
|
|
@ -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_ */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -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() {}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
||||||
|
|
|
@ -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 =
|
|
@ -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:
|
|
@ -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\">";
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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 << "?>";
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
Loading…
Reference in New Issue