Zypp Commits
Threads by month
- ----- 2024 -----
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
February 2009
- 7 participants
- 171 discussions
![](https://seccdn.libravatar.org/avatar/03f46662129c78729420d160bdff6dd0.jpg?s=120&d=mm&r=g)
06 Feb '09
ref: refs/heads/SuSE-Code-11-Branch
commit a7b9c56de902a2ac97d37693b47c9a5b3714b4f2
Author: Stefan Schubert <schubi(a)suse.de>
Date: Fri Feb 6 11:38:18 2009 +0100
updated translations
---
package/libzypp.changes | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/package/libzypp.changes b/package/libzypp.changes
index c9d6fe7..e4e0b2a 100644
--- a/package/libzypp.changes
+++ b/package/libzypp.changes
@@ -1,4 +1,9 @@
-------------------------------------------------------------------
+Fri Feb 6 11:38:00 CET 2009 - schubi(a)suse.de
+
+- updated translations
+
+-------------------------------------------------------------------
Tue Feb 3 16:58:07 CET 2009 - ma(a)suse.de
- Send any output from rpm install/delete scripts via callback, so
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
![](https://seccdn.libravatar.org/avatar/bbcc248607dd5cc3db5ea99581004c2c.jpg?s=120&d=mm&r=g)
[zypp-commit] <libzypp> master : add url() to webserver so we can detect hostname and jump over the ipv6
by Duncan Mac-Vicar P 05 Feb '09
by Duncan Mac-Vicar P 05 Feb '09
05 Feb '09
ref: refs/heads/master
commit b1d894c4dbcc4a9ea1f45e2a365616cbfae58adb
Author: Duncan Mac-Vicar P <dmacvicar(a)suse.de>
Date: Thu Feb 5 18:45:10 2009 +0100
add url() to webserver so we can detect hostname and jump over the ipv6
breakage when using localhost
---
tests/lib/WebServer.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++
tests/lib/WebServer.h | 11 +++++++++++
tests/zypp/Fetcher_test.cc | 4 ++--
3 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/tests/lib/WebServer.cc b/tests/lib/WebServer.cc
index 426b08e..15d9430 100644
--- a/tests/lib/WebServer.cc
+++ b/tests/lib/WebServer.cc
@@ -14,6 +14,17 @@
using namespace zypp;
using namespace std;
+static inline string hostname()
+{
+ static char buf[256];
+ string result;
+ if (!::gethostname(buf, 255))
+ result += string(buf);
+ else
+ return "localhost";
+ return result;
+}
+
#define WEBRICK 1
class WebServer::Impl
@@ -36,6 +47,13 @@ public:
virtual void worker_thread()
{}
+
+ virtual int port() const
+ {
+ return 0;
+ }
+
+
private:
friend Impl * rwcowClone<Impl>( const Impl * rhs );
@@ -57,6 +75,12 @@ public:
if ( ! _stopped )
stop();
}
+
+ virtual int port() const
+ {
+ return _port;
+ }
+
virtual void worker_thread()
{
@@ -145,6 +169,12 @@ public:
mg_set_option(_ctx, "root", _docroot.c_str());
_stopped = false;
}
+
+ virtual int port() const
+ {
+ return _port;
+ }
+
virtual string log() const
{
@@ -188,6 +218,20 @@ std::string WebServer::log() const
return _pimpl->log();
}
+int WebServer::port() const
+{
+ return _pimpl->port();
+}
+
+
+Url WebServer::url() const
+{
+ Url url;
+ url.setHost(hostname());
+ url.setPort(str::numstring(port()));
+ url.setScheme("http");
+ return url;
+}
void WebServer::stop()
{
diff --git a/tests/lib/WebServer.h b/tests/lib/WebServer.h
index e7c5420..ec62e41 100644
--- a/tests/lib/WebServer.h
+++ b/tests/lib/WebServer.h
@@ -5,6 +5,7 @@
#include "boost/thread.hpp"
#include "boost/smart_ptr.hpp"
+#include "zypp/Url.h"
#include "zypp/Pathname.h"
#include "zypp/base/PtrTypes.h"
@@ -48,6 +49,16 @@ class WebServer
* Stops the worker thread
*/
void stop();
+
+ /**
+ * returns the port we are listening to
+ */
+ int port() const;
+
+ /**
+ * returns the base url where the webserver is listening
+ */
+ zypp::Url url() const;
/**
* shows the log of last run
diff --git a/tests/zypp/Fetcher_test.cc b/tests/zypp/Fetcher_test.cc
index c663c11..c7af0a4 100644
--- a/tests/zypp/Fetcher_test.cc
+++ b/tests/zypp/Fetcher_test.cc
@@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE(enqueuedir_http)
WebServer web((Pathname(TESTS_SRC_DIR) + "/zypp/data/Fetcher/remote-site").c_str(), 10001);
web.start();
- MediaSetAccess media( Url("http://localhost:10001"), "/" );
+ MediaSetAccess media( web.url(), "/" );
Fetcher fetcher;
filesystem::TmpDir dest;
@@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(enqueuedir_http_broken)
WebServer web((Pathname(TESTS_SRC_DIR) + "/zypp/data/Fetcher/remote-site").c_str() , 10001 );
web.start();
- MediaSetAccess media( Url("http://localhost:10001"), "/" );
+ MediaSetAccess media( web.url(), "/" );
Fetcher fetcher;
filesystem::TmpDir dest;
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
![](https://seccdn.libravatar.org/avatar/e6d0c9f42625f8f9f45b6bd11ffbb77b.jpg?s=120&d=mm&r=g)
[zypp-commit] <cmpi-zypp> master : make zyppACInit() a private function
by Michael Calmer 05 Feb '09
by Michael Calmer 05 Feb '09
05 Feb '09
ref: refs/heads/master
commit de080c17ea3edb7cc336432bb8d20bd5ab1689b8
Author: Michael Calmer <mc(a)suse.de>
Date: Thu Feb 5 18:08:35 2009 +0100
make zyppACInit() a private function
move zyppACInit() out of the private namespace and make it a normal
private function.
add sysRoot as member of ZyppAC and implement a get method to make
this Pathname available.
---
src/SUSE_zypp.cc | 32 +++++++++++++++++---------------
src/SUSE_zypp.h | 6 ++++++
2 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/src/SUSE_zypp.cc b/src/SUSE_zypp.cc
index bd8d12b..a3d71cc 100644
--- a/src/SUSE_zypp.cc
+++ b/src/SUSE_zypp.cc
@@ -23,14 +23,28 @@ namespace cmpizypp
int initonce = _initonce();
- const Pathname sysRoot( getenv("CMPIZYPP_ROOT") ? getenv("CMPIZYPP_ROOT") : "/" );
bool zyppACInitialized = false;
- void zyppACInit()
- {
+
+ } // namespace
+
+
+ ZyppAC::ZyppAC()
+ {
+ zyppACInit();
+ }
+
+ ZyppAC::~ZyppAC()
+ {
+ }
+
+ void ZyppAC::zyppACInit()
+ {
if ( zyppACInitialized )
return;
+ sysRoot = Pathname( getenv("CMPIZYPP_ROOT") ? getenv("CMPIZYPP_ROOT") : "/" );
+
KeyRing::setDefaultAccept( KeyRing::ACCEPT_UNKNOWNKEY|KeyRing::TRUST_KEY_TEMPORARILY );
// Load Target
@@ -89,18 +103,6 @@ namespace cmpizypp
USR << "pool: " << pool << endl;
zyppACInitialized = true;
- }
-
- } // namespace
-
-
- ZyppAC::ZyppAC()
- {
- zyppACInit();
- }
-
- ZyppAC::~ZyppAC()
- {
}
std::string ZyppAC::exceptionString( const Exception & err_r, const std::string & prefix_r )
diff --git a/src/SUSE_zypp.h b/src/SUSE_zypp.h
index 69812bc..2ccd7f5 100644
--- a/src/SUSE_zypp.h
+++ b/src/SUSE_zypp.h
@@ -17,10 +17,16 @@ namespace cmpizypp
/** Access to libzypp components. */
class ZyppAC
{
+ private:
+ zypp::Pathname sysRoot;
+
+ void zyppACInit();
+
public:
ZyppAC();
~ZyppAC();
+ zypp::Pathname getSysRoot() const { return sysRoot; }
zypp::Target & target() const { return *zypp::getZYpp()->getTarget(); }
zypp::ResPool pool() const { return zypp::ResPool::instance(); }
zypp::ResPoolProxy poolProxy() const { return pool().proxy(); }
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
![](https://seccdn.libravatar.org/avatar/e6d0c9f42625f8f9f45b6bd11ffbb77b.jpg?s=120&d=mm&r=g)
05 Feb '09
ref: refs/heads/master
commit 3a0944e3fa291aca1eb77d6ac9a644bfafc588ff
Author: Michael Calmer <mc(a)suse.de>
Date: Thu Feb 5 18:06:27 2009 +0100
implement SUSE_SoftwareRepository
---
mof/CMakeLists.txt | 2 +
mof/SUSE_SoftwareRepository.mof | 64 +++++++
mof/SUSE_SoftwareRepository.sfcb.reg | 5 +
mof/deploy.mof | 1 +
src/CMakeLists.txt | 2 +
src/SUSE_SoftwareRepositoryProvider.cc | 302 ++++++++++++++++++++++++++++++++
src/SUSE_SoftwareRepositoryProvider.h | 32 ++++
7 files changed, 408 insertions(+), 0 deletions(-)
diff --git a/mof/CMakeLists.txt b/mof/CMakeLists.txt
index 6c7b91b..4af9285 100644
--- a/mof/CMakeLists.txt
+++ b/mof/CMakeLists.txt
@@ -20,6 +20,8 @@ INSTALL( FILES
SUSE_ElementCapabilities.sfcb.reg
SUSE_HostedInstallationService.mof
SUSE_HostedInstallationService.sfcb.reg
+ SUSE_SoftwareRepository.mof
+ SUSE_SoftwareRepository.sfcb.reg
deploy.mof
DESTINATION ${CMPIZYPP_DATA_DIR}/
)
diff --git a/mof/SUSE_SoftwareRepository.mof b/mof/SUSE_SoftwareRepository.mof
new file mode 100644
index 0000000..b376678
--- /dev/null
+++ b/mof/SUSE_SoftwareRepository.mof
@@ -0,0 +1,64 @@
+// ==================================================================
+// SUSE_SoftwareRepository
+// ==================================================================
+ [Experimental, Version ( "2.10.0" ),
+ Description (
+ "SoftwareRepository describes the URL of a repository "
+ "containing SoftwareIdentities "
+ "for use by the SoftwareInstallationService. " )]
+class SUSE_SoftwareRepository : CIM_RemoteServiceAccessPoint {
+
+ [Override ( "InfoFormat" ),
+ Description (
+ "A SoftwareRepository will always be a URL." )]
+ uint16 InfoFormat = 200;
+
+ [Description (
+ "An enumerated integer that specifies the type of "
+ "resource referenced by the "
+ "RemoteServiceAccessPoint.AccessInfo property." ),
+ ValueMap { "0", "1", "2", "3", "4", "5", "6", "7", "9", "10",
+ "11", "12", "..", "0x8000..0xFFFF" },
+ Values { "Unknown", "Other", "Installer and Payload",
+ "Installer", "Payload", "Installability checker",
+ "Security Advisory", "Engineering Advisory",
+ "Technical release notes", "Change notification",
+ "Whitepaper", "Marketing Documentation", "DMTF Reserved",
+ "Vendor Reserved" },
+ ModelCorrespondence {
+ "CIM_SoftwareIdentityResource.OtherResourceType",
+ "CIM_SoftwareIdentityResource.ExtendedResourceType" }]
+ uint16 ResourceType = 1;
+
+ [Description (
+ "A enumerated integer that provides further information "
+ "for ResourceType. It will set to 2 (\'Not Applicable\') "
+ "if there is no extended information available." ),
+ ValueMap { "0", "2", // Binary format types
+ "3",
+ "4", "5", "6", "7", "8", "9..100", "101..200",
+ //Text formats
+ "201", "202", "203",
+ "204..0x7FFF", "0x8000..0xFFFF" },
+ Values { "Unknown", "Not Applicable",
+ // Binary format types
+ "Linux RPM",
+ "HP-UX Depot", "Windows MSI", "Solaris Package",
+ "Macintosh Disk Image", "Debian linux Package",
+ "DMTF Reserved", "Vendor Reserved",
+ //Text formats
+ "HTML", "PDF", "Text File",
+ "DMTF Reserved", "Vendor Reserved" },
+ ModelCorrespondence {
+ "CIM_SoftwareIdentityResource.ResourceType" }]
+ uint16 ExtendedResourceType;
+
+ [Description (
+ "A string describing the file type when the instance\'s "
+ "ResourceType property is 1 (\"Other\")." ),
+ ModelCorrespondence {
+ "CIM_SoftwareIdentityResource.ResourceType" }]
+ string OtherResourceType = "Software Repository";
+
+
+};
diff --git a/mof/SUSE_SoftwareRepository.sfcb.reg b/mof/SUSE_SoftwareRepository.sfcb.reg
new file mode 100644
index 0000000..1a8c53d
--- /dev/null
+++ b/mof/SUSE_SoftwareRepository.sfcb.reg
@@ -0,0 +1,5 @@
+[SUSE_SoftwareRepository]
+ provider: SUSE_SoftwareRepositoryProvider
+ location: cmpi-zypp
+ type: instance method
+ namespace: root/cimv2
diff --git a/mof/deploy.mof b/mof/deploy.mof
index dcf1632..216fd85 100644
--- a/mof/deploy.mof
+++ b/mof/deploy.mof
@@ -9,4 +9,5 @@
#pragma include ("SUSE_SoftwareInstallationServiceCapabilities.mof")
#pragma include ("SUSE_ElementCapabilities.mof")
#pragma include ("SUSE_HostedInstallationService.mof")
+#pragma include ("SUSE_SoftwareRepository.mof")
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 636e441..6956fe7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -19,6 +19,7 @@ SET( CMPIZYPP_SRCS
SUSE_SoftwareInstallationServiceCapabilitiesProvider.cc
SUSE_ElementCapabilitiesProvider.cc
SUSE_HostedInstallationServiceProvider.cc
+ SUSE_SoftwareRepositoryProvider.cc
)
SET( CMPIZYPP_HEADERS
SUSE_Common.h
@@ -34,6 +35,7 @@ SET( CMPIZYPP_HEADERS
SUSE_SoftwareInstallationServiceCapabilitiesProvider.h
SUSE_ElementCapabilitiesProvider.h
SUSE_HostedInstallationServiceProvider.h
+ SUSE_SoftwareRepositoryProvider.h
)
ADD_LIBRARY(cmpi-zypp SHARED ${CMPIZYPP_SRCS})
diff --git a/src/SUSE_SoftwareRepositoryProvider.cc b/src/SUSE_SoftwareRepositoryProvider.cc
new file mode 100644
index 0000000..7b2d311
--- /dev/null
+++ b/src/SUSE_SoftwareRepositoryProvider.cc
@@ -0,0 +1,302 @@
+
+#include <iostream>
+
+#include <cmpi/cmpimacs.h>
+#include <cmpi/cmpidt.h>
+#include <cmpi/CmpiResult.h>
+#include <cmpi/CmpiBroker.h>
+#include <cmpi/CmpiArray.h>
+#include <cmpi/CmpiBooleanData.h>
+
+#include <zypp/base/String.h>
+#include <zypp/base/LogTools.h>
+
+#include "SUSE_zypp.h"
+#include "SUSE_Common.h"
+#include "SUSE_SoftwareRepositoryProvider.h"
+
+using namespace zypp;
+using std::endl;
+
+namespace cmpizypp
+{
+ namespace
+ {
+ const char * _ClassName = "SUSE_SoftwareRepository";
+ } // namespace
+
+
+SUSE_SoftwareRepositoryProviderClass::SUSE_SoftwareRepositoryProviderClass( const CmpiBroker & mbp, const CmpiContext & ctx )
+ : CmpiBaseMI( mbp, ctx )
+ , CmpiInstanceMI( mbp, ctx )
+ , CmpiMethodMI( mbp, ctx )
+{
+}
+
+CmpiStatus SUSE_SoftwareRepositoryProviderClass::enumInstanceNames( const CmpiContext& ctx, CmpiResult& rslt, const CmpiObjectPath & cop )
+{
+ _CMPIZYPP_TRACE(1,("--- %s CMPI EnumInstanceNames() called",_ClassName));
+
+ CmpiObjectPath csop = get_this_computersystem(*broker, ctx, cop);
+ const char *sccn = csop.getKey("CreationClassName");
+ const char *sn = csop.getKey("Name");
+
+ // zypp init
+ zypp::scoped_ptr<ZyppAC> zyppac;
+ try
+ {
+ zyppac.reset( new ZyppAC() );
+ }
+ catch ( const zypp::Exception & err )
+ {
+ CmpiStatus rc( CMPI_RC_ERR_FAILED, ZyppAC::exceptionString( err, "Could not list software identities: " ).c_str() );
+ _CMPIZYPP_TRACE(1,("--- %s CMPI EnumInstanceNames() failed : %s", _ClassName, rc.msg()));
+ return rc;
+ }
+
+ RepoManager repoManager( zyppac->getSysRoot() );
+
+ RepoInfoList repos = repoManager.knownRepositories();
+ for ( RepoInfoList::iterator it = repos.begin(); it != repos.end(); ++it )
+ {
+ CmpiObjectPath op( cop.getNameSpace(), _ClassName );
+ op.setKey( "SystemCreationClassName", sccn);
+ op.setKey( "SystemName", sn);
+ op.setKey( "CreationClassName", _ClassName);
+ op.setKey( "Name", it->alias().c_str() );
+ rslt.returnData( op );
+ }
+
+ rslt.returnDone();
+ _CMPIZYPP_TRACE(1,("--- %s CMPI EnumInstanceNames() exited",_ClassName));
+ return CmpiStatus(CMPI_RC_OK);
+}
+
+CmpiStatus SUSE_SoftwareRepositoryProviderClass::enumInstances( const CmpiContext & ctx, CmpiResult & rslt, const CmpiObjectPath & cop, const char** properties )
+{
+ _CMPIZYPP_TRACE(1,("--- %s CMPI EnumInstances() called",_ClassName));
+
+ CmpiObjectPath csop = get_this_computersystem(*broker, ctx, cop);
+
+ // zypp init
+ zypp::scoped_ptr<ZyppAC> zyppac;
+ try
+ {
+ zyppac.reset( new ZyppAC() );
+ }
+ catch ( const zypp::Exception & err )
+ {
+ CmpiStatus rc( CMPI_RC_ERR_FAILED, ZyppAC::exceptionString( err, "Could not list software identities: " ).c_str() );
+ _CMPIZYPP_TRACE(1,("--- %s CMPI EnumInstanceNames() failed : %s", _ClassName, rc.msg()));
+ return rc;
+ }
+
+ RepoManager repoManager( zyppac->getSysRoot() );
+
+ RepoInfoList repos = repoManager.knownRepositories();
+ for ( RepoInfoList::iterator it = repos.begin(); it != repos.end(); ++it )
+ {
+ rslt.returnData( makeInstance( *it, cop, csop, properties ) );
+ }
+
+ rslt.returnDone();
+ _CMPIZYPP_TRACE(1,("--- %s CMPI EnumInstances() exited",_ClassName));
+ return CmpiStatus(CMPI_RC_OK);
+}
+
+
+CmpiStatus SUSE_SoftwareRepositoryProviderClass::getInstance( const CmpiContext &ctx, CmpiResult &rslt, const CmpiObjectPath &cop, const char **properties )
+{
+ _CMPIZYPP_TRACE(1,("--- %s CMPI GetInstance() called",_ClassName));
+
+ const char *lsccn = cop.getKey("SystemCreationClassName");
+ const char *lsn = cop.getKey("SystemName");
+ const char *lccn = cop.getKey("CreationClassName");
+ const char *ln = cop.getKey("Name");
+
+ CmpiObjectPath csop = get_this_computersystem(*broker, ctx, cop);
+ const char *sccn = csop.getKey("CreationClassName");
+ const char *sn = csop.getKey("Name");
+
+ if( lsccn== NULL || lsn == NULL || lccn == NULL || ln == NULL ||
+ ::strcmp(lccn, _ClassName) != 0 ||
+ ::strcmp(lsccn, sccn) != 0 || ::strcmp(lsn, sn) != 0)
+ {
+ CmpiStatus rc( CMPI_RC_ERR_FAILED, "Could not find this instance." );
+ _CMPIZYPP_TRACE(1,("--- %s CMPI GetInstance() failed : %s", _ClassName, rc.msg()));
+ return rc;
+ }
+
+ // zypp init
+ zypp::scoped_ptr<ZyppAC> zyppac;
+ try
+ {
+ zyppac.reset( new ZyppAC() );
+ }
+ catch ( const zypp::Exception & err )
+ {
+ CmpiStatus rc( CMPI_RC_ERR_FAILED, ZyppAC::exceptionString( err, "Could not list software identities: " ).c_str() );
+ _CMPIZYPP_TRACE(1,("--- %s CMPI EnumInstanceNames() failed : %s", _ClassName, rc.msg()));
+ return rc;
+ }
+
+ RepoManager repoManager( zyppac->getSysRoot() );
+ if( ! repoManager.hasRepo( ln ) )
+ {
+ CmpiStatus rc( CMPI_RC_ERR_FAILED, "Could not find this instance." );
+ _CMPIZYPP_TRACE(1,("--- %s CMPI GetInstance() failed : %s", _ClassName, rc.msg()));
+ return rc;
+ }
+ RepoInfo repo( repoManager.getRepo( ln ) );
+
+ rslt.returnData( makeInstance( repo, cop, csop, properties ) );
+
+ rslt.returnDone();
+ _CMPIZYPP_TRACE(1,("--- %s CMPI GetInstance() exited",_ClassName));
+ return CmpiStatus(CMPI_RC_OK);
+}
+
+CmpiStatus SUSE_SoftwareRepositoryProviderClass::invokeMethod (const CmpiContext &ctx, CmpiResult &rslt,
+ const CmpiObjectPath &ref, const char *methodName,
+ const CmpiArgs &in, CmpiArgs &out)
+{
+ _CMPIZYPP_TRACE(1,("--- %s CMPI invokeMethod() called with method: %s",_ClassName, methodName));
+
+ if( ::strcasecmp( ref.getClassName().charPtr(), _ClassName) != 0 )
+ {
+ return CmpiStatus(CMPI_RC_ERR_NOT_SUPPORTED, "invalid classname");
+ }
+ CmpiStatus st(CMPI_RC_ERR_NOT_SUPPORTED);
+
+ if( ::strcasecmp( methodName, "RequestStateChange" ) == 0)
+ {
+ const char *lsccn = ref.getKey("SystemCreationClassName");
+ const char *lsn = ref.getKey("SystemName");
+ const char *lccn = ref.getKey("CreationClassName");
+ const char *ln = ref.getKey("Name");
+
+ CmpiObjectPath csop = get_this_computersystem(*broker, ctx, ref);
+ const char *sccn = csop.getKey("CreationClassName");
+ const char *sn = csop.getKey("Name");
+
+ if( lsccn== NULL || lsn == NULL || lccn == NULL || ln == NULL ||
+ ::strcmp(lccn, _ClassName) != 0 ||
+ ::strcmp(lsccn, sccn) != 0 || ::strcmp(lsn, sn) != 0)
+ {
+ CmpiStatus rc( CMPI_RC_ERR_FAILED, "Could not find this instance." );
+ _CMPIZYPP_TRACE(1,("--- %s CMPI GetInstance() failed : %s", _ClassName, rc.msg()));
+ return rc;
+ }
+
+ CMPIUint16 reqState = 0;
+ try
+ {
+ reqState = in.getArg("RequestedState");
+ }
+ catch(CmpiStatus rc)
+ {
+ CmpiStatus rc( CMPI_RC_ERR_FAILED, "Missing parameter RequestedState." );
+ _CMPIZYPP_TRACE(1,("--- %s CMPI GetInstance() failed : %s", _ClassName, rc.msg()));
+ return rc;
+ }
+ // zypp init
+ zypp::scoped_ptr<ZyppAC> zyppac;
+ try
+ {
+ zyppac.reset( new ZyppAC() );
+ }
+ catch ( const zypp::Exception & err )
+ {
+ CmpiStatus rc( CMPI_RC_ERR_FAILED, ZyppAC::exceptionString( err, "Could not list software identities: " ).c_str() );
+ _CMPIZYPP_TRACE(1,("--- %s CMPI EnumInstanceNames() failed : %s", _ClassName, rc.msg()));
+ return rc;
+ }
+ bool newStateEnabled = true;
+
+ if( reqState == 2 )
+ newStateEnabled = true;
+ else if( reqState == 3 )
+ newStateEnabled = false;
+ else
+ {
+ _CMPIZYPP_TRACE(1,("--- %s CMPI GetInstance() failed : Invalid Parameter.", _ClassName ));
+ rslt.returnData( CMPIUint32(5) ); // invalid Parameter
+ rslt.returnDone();
+ return CmpiStatus ( CMPI_RC_OK );
+ }
+
+ RepoManager repoManager( zyppac->getSysRoot() );
+ if( ! repoManager.hasRepo( ln ) )
+ {
+ _CMPIZYPP_TRACE(1,("--- %s CMPI GetInstance() failed : Could not find this instance.", _ClassName ));
+ rslt.returnData( CMPIUint32(2) ); // unknown Error
+ rslt.returnDone();
+ return CmpiStatus ( CMPI_RC_OK );
+ }
+ try
+ {
+ RepoInfo repo( repoManager.getRepo( ln ) );
+ repo.setEnabled( newStateEnabled );
+ repoManager.modifyRepository( repo );
+ }
+ catch( const zypp::Exception & err )
+ {
+ _CMPIZYPP_TRACE(1,("--- %s CMPI InvokeMethod() failed : %s ", _ClassName,
+ ZyppAC::exceptionString( err, "" ).c_str() ));
+ rslt.returnData( CMPIUint32(2) ); // unknown Error
+ rslt.returnDone();
+ return CmpiStatus ( CMPI_RC_OK );
+ }
+ rslt.returnData( CmpiData(CMPIUint32(0)) ); // Completed with No Error
+ rslt.returnDone();
+ return CmpiStatus ( CMPI_RC_OK );
+ }
+
+ _CMPIZYPP_TRACE(1,("--- %s CMPI invokeMethod() exited",_ClassName));
+ return st;
+}
+
+/* ========================= private ================================== */
+
+CmpiInstance SUSE_SoftwareRepositoryProviderClass::makeInstance( const RepoInfo &repo,
+ const CmpiObjectPath & cop,
+ const CmpiObjectPath & csop,
+ const char ** properties )
+{
+ CmpiObjectPath op( cop.getNameSpace(), _ClassName );
+ CmpiInstance ci( op );
+
+ const char *sccn = csop.getKey("CreationClassName");
+ const char *sn = csop.getKey("Name");
+
+ const char * keys[] = { "SystemCreationClassName", "SystemName", "CreationClassName", "Name" };
+ ci.setPropertyFilter( properties, keys );
+
+ ci.setProperty( "SystemCreationClassName", sccn);
+ ci.setProperty( "SystemName", sn);
+ ci.setProperty( "CreationClassName", _ClassName);
+ ci.setProperty( "Name", repo.alias().c_str() );
+
+ ci.setProperty( "AccessInfo", repo.url().asString().c_str() );
+
+ CmpiArray avReqState( 2, CMPI_uint16 );
+ avReqState[0] = CMPIUint16(2); // Enabled
+ avReqState[1] = CMPIUint16(3); // Disabled
+ ci.setProperty( "AvailableRequestedStates", avReqState );
+
+ ci.setProperty( "Caption", "Software Repository" );
+ ci.setProperty( "Description", (repo.name() + " Software Repository").c_str() );
+ ci.setProperty( "ElementName", repo.name().c_str() );
+ ci.setProperty( "EnabledDefault", CMPIUint16(7) );
+ ci.setProperty( "EnabledState", (repo.enabled())?CMPIUint16(2):CMPIUint16(3) );
+ ci.setProperty( "ExtendedResourceType", CMPIUint16(2) );
+
+ return ci;
+}
+
+} // namespace cmpizypp
+
+CMProviderBase( SUSE_SoftwareRepositoryProvider );
+
+CMInstanceMIFactory( cmpizypp::SUSE_SoftwareRepositoryProviderClass, SUSE_SoftwareRepositoryProvider );
+CMMethodMIFactory( cmpizypp::SUSE_SoftwareRepositoryProviderClass, SUSE_SoftwareRepositoryProvider );
diff --git a/src/SUSE_SoftwareRepositoryProvider.h b/src/SUSE_SoftwareRepositoryProvider.h
new file mode 100644
index 0000000..80e1985
--- /dev/null
+++ b/src/SUSE_SoftwareRepositoryProvider.h
@@ -0,0 +1,32 @@
+#ifndef SUSE_SOFTWAREREPOSITORYPROVIDER_H
+#define SUSE_SOFTWAREREPOSITORYPROVIDER_H
+
+#include <cmpi/CmpiInstanceMI.h>
+#include <cmpi/CmpiMethodMI.h>
+#include <zypp/RepoInfo.h>
+
+namespace cmpizypp
+{
+ /**
+ */
+ class SUSE_SoftwareRepositoryProviderClass : public CmpiInstanceMI, public CmpiMethodMI
+ {
+ public:
+ SUSE_SoftwareRepositoryProviderClass( const CmpiBroker & mbp, const CmpiContext & ctx );
+
+ virtual CmpiStatus enumInstanceNames( const CmpiContext& ctx, CmpiResult& rslt, const CmpiObjectPath & cop );
+ virtual CmpiStatus enumInstances( const CmpiContext & ctx, CmpiResult & rslt, const CmpiObjectPath & cop, const char** properties );
+ virtual CmpiStatus getInstance( const CmpiContext &ctx, CmpiResult &rslt, const CmpiObjectPath &cop, const char **properties );
+
+ virtual CmpiStatus invokeMethod (const CmpiContext &ctx, CmpiResult &rslt,
+ const CmpiObjectPath &ref, const char *methodName,
+ const CmpiArgs &in, CmpiArgs &out);
+
+ private:
+ CmpiInstance makeInstance( const zypp::RepoInfo &repo, const CmpiObjectPath &cop,
+ const CmpiObjectPath &csop, const char ** properties );
+ };
+
+} // namespace cmpizypp
+
+#endif // SUSE_SOFTWAREREPOSITORYPROVIDER_H
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
![](https://seccdn.libravatar.org/avatar/bbcc248607dd5cc3db5ea99581004c2c.jpg?s=120&d=mm&r=g)
[zypp-commit] <libzypp> master : use which instead of whereis, at least gives a error code back
by Duncan Mac-Vicar P 05 Feb '09
by Duncan Mac-Vicar P 05 Feb '09
05 Feb '09
ref: refs/heads/master
commit 745e6e1a0fe7e53379e0dee651a1ca1880036479
Author: Duncan Mac-Vicar P <dmacvicar(a)suse.de>
Date: Thu Feb 5 18:05:38 2009 +0100
use which instead of whereis, at least gives a error code back
---
zypp/media/MediaAria2c.cc | 25 +++++++------------------
1 files changed, 7 insertions(+), 18 deletions(-)
diff --git a/zypp/media/MediaAria2c.cc b/zypp/media/MediaAria2c.cc
index 8720c7f..3ae518e 100644
--- a/zypp/media/MediaAria2c.cc
+++ b/zypp/media/MediaAria2c.cc
@@ -63,20 +63,13 @@ MediaAria2c::existsAria2cmd()
{
const char* argv[] =
{
- "whereis",
- "-b",
+ "which",
"aria2c",
NULL
};
ExternalProgram aria(argv, ExternalProgram::Stderr_To_Stdout);
-
- std::string ariaResponse( aria.receiveLine());
- string::size_type pos = ariaResponse.find('/', 0 );
- if( pos != string::npos )
- return true;
- else
- return false;
+ return ( aria.close() == 0 );
}
static const char *const anonymousIdHeader()
@@ -610,8 +603,7 @@ Pathname MediaAria2c::whereisAria2c()
const char* argv[] =
{
- "whereis",
- "-b",
+ "which",
"aria2c",
NULL
};
@@ -619,15 +611,12 @@ Pathname MediaAria2c::whereisAria2c()
ExternalProgram aria(argv, ExternalProgram::Stderr_To_Stdout);
std::string ariaResponse( aria.receiveLine());
- aria.close();
+ int code = aria.close();
- string::size_type pos = ariaResponse.find('/', 0 );
- if( pos != string::npos )
+ if( code == 0 )
{
- aria2cPathr = ariaResponse;
- string::size_type pose = ariaResponse.find(' ', pos + 1 );
- aria2cPathr = ariaResponse.substr( pos , pose - pos );
- MIL << "We will use aria2c located here: " << ariaResponse.substr( pos , pose - pos) << endl;
+ aria2cPathr = str::trim(ariaResponse);
+ MIL << "We will use aria2c located here: " << aria2cPathr << endl;
}
else
{
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
![](https://seccdn.libravatar.org/avatar/bbcc248607dd5cc3db5ea99581004c2c.jpg?s=120&d=mm&r=g)
[zypp-commit] <libzypp> master : Require aria now that it is default
by Duncan Mac-Vicar P 05 Feb '09
by Duncan Mac-Vicar P 05 Feb '09
05 Feb '09
ref: refs/heads/master
commit fa3dca7b799fd03caad75cf10cf08ffc2b08facc
Author: Duncan Mac-Vicar P <dmacvicar(a)suse.de>
Date: Thu Feb 5 16:50:32 2009 +0100
Require aria now that it is default
---
libzypp.spec.cmake | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/libzypp.spec.cmake b/libzypp.spec.cmake
index 159c123..747bedc 100644
--- a/libzypp.spec.cmake
+++ b/libzypp.spec.cmake
@@ -29,7 +29,7 @@ BuildRequires: libsatsolver-devel >= 0.13.0 openssl-devel
BuildRequires: boost-devel curl-devel dejagnu doxygen gcc-c++ gettext-devel graphviz hal-devel libxml2-devel
# required for testsuite, webrick
-BuildRequires: ruby
+BuildRequires: ruby aria2
%if 0%{?suse_version}
BuildRequires: libexpat-devel
@@ -53,8 +53,6 @@ BuildRequires: librpm-devel
Requires: e2fsprogs
%endif
-
-
%if 0%{?suse_version}
Requires: gpg2
%else
@@ -62,6 +60,8 @@ Requires: gnupg
%endif
%requires_eq satsolver-tools
+Requires: aria2
+
%description
Package, Patch, Pattern, and Product Management
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
![](https://seccdn.libravatar.org/avatar/bbcc248607dd5cc3db5ea99581004c2c.jpg?s=120&d=mm&r=g)
[zypp-commit] <libzypp> master : Forgot to include mongoose (new shttpd name)
by Duncan Mac-Vicar P 05 Feb '09
by Duncan Mac-Vicar P 05 Feb '09
05 Feb '09
ref: refs/heads/master
commit 09cef514dc511e6d6ca5e11e6e6d2a4691fb298e
Author: Duncan Mac-Vicar P <dmacvicar(a)suse.de>
Date: Thu Feb 5 15:59:29 2009 +0100
Forgot to include mongoose (new shttpd name)
---
vendor/mongoose/CMakeLists.txt | 9 +
vendor/mongoose/mongoose.c | 3758 ++++++++++++++++++++++++++++++++++++++++
vendor/mongoose/mongoose.h | 139 ++
vendor/shttpd/CMakeLists.txt | 29 -
vendor/shttpd/auth.c | 419 -----
vendor/shttpd/cgi.c | 229 ---
vendor/shttpd/compat_rtems.c | 198 ---
vendor/shttpd/compat_rtems.h | 60 -
vendor/shttpd/compat_unix.c | 128 --
vendor/shttpd/compat_unix.h | 35 -
vendor/shttpd/compat_win32.c | 687 --------
vendor/shttpd/compat_win32.h | 83 -
vendor/shttpd/compat_wince.c | 1593 -----------------
vendor/shttpd/compat_wince.h | 145 --
vendor/shttpd/config.h | 30 -
vendor/shttpd/defs.h | 395 -----
vendor/shttpd/io.h | 97 -
vendor/shttpd/io_cgi.c | 127 --
vendor/shttpd/io_dir.c | 153 --
vendor/shttpd/io_emb.c | 291 ----
vendor/shttpd/io_file.c | 157 --
vendor/shttpd/io_socket.c | 39 -
vendor/shttpd/io_ssi.c | 488 ------
vendor/shttpd/io_ssl.c | 85 -
vendor/shttpd/llist.h | 59 -
vendor/shttpd/log.c | 93 -
vendor/shttpd/md5.c | 249 ---
vendor/shttpd/md5.h | 24 -
vendor/shttpd/shttpd.c | 1903 --------------------
vendor/shttpd/shttpd.h | 111 --
vendor/shttpd/ssl.h | 52 -
vendor/shttpd/standalone.c | 72 -
vendor/shttpd/std_includes.h | 40 -
vendor/shttpd/string.c | 95 -
34 files changed, 3906 insertions(+), 8166 deletions(-)
diff --git a/vendor/mongoose/CMakeLists.txt b/vendor/mongoose/CMakeLists.txt
new file mode 100644
index 0000000..ee7268f
--- /dev/null
+++ b/vendor/mongoose/CMakeLists.txt
@@ -0,0 +1,9 @@
+ADD_DEFINITIONS( -DNO_CGI -D_POSIX_SOURCE -D_BSD_SOURCE )
+SET(mongoose_SOURCES
+ mongoose.c
+ mongoose.h
+)
+
+ADD_LIBRARY(mongoose ${mongoose_SOURCES})
+TARGET_LINK_LIBRARIES(mongoose dl pthread)
+
diff --git a/vendor/mongoose/mongoose.c b/vendor/mongoose/mongoose.c
new file mode 100644
index 0000000..8e291c4
--- /dev/null
+++ b/vendor/mongoose/mongoose.c
@@ -0,0 +1,3758 @@
+/*
+ * Copyright (c) 2004-2009 Sergey Lyubka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#endif /* _WIN32_WCE */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#if defined(_WIN32) /* Windows specific */
+#include <windows.h>
+
+#ifndef _WIN32_WCE
+#include <process.h>
+#include <direct.h>
+#include <io.h>
+#else /* _WIN32_WCE */
+/* Windows CE-specific definitions */
+#define NO_CGI /* WinCE has no pipes */
+#define NO_GUI /* temporarily until it is fixed */
+/* WinCE has both Unicode and ANSI versions of GetProcAddress */
+#undef GetProcAddress
+#define GetProcAddress GetProcAddressA
+#endif /* _WIN32_WCE */
+
+/*
+ * Do not allow holes in data structures!
+ * This is needed so when Mongoose DLL is loaded, other languages that
+ * describe struct mg_request_info from mongoose.h, agree with C code.
+ */
+#pragma pack(1)
+
+#define __func__ __FUNCTION__
+#define ERRNO GetLastError()
+#define NO_SOCKLEN_T
+#define SSL_LIB "ssleay32.dll"
+#define DIRSEP '\\'
+#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
+#define O_NONBLOCK 0
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define dlopen(x,y) LoadLibrary(x)
+#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
+#define _POSIX_
+
+#if !defined(R_OK)
+#define R_OK 04 /* for _access() */
+#endif /* !R_OK MINGW #defines R_OK */
+
+#define SHUT_WR 1
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#define popen(x, y) _popen(x, y)
+#define pclose(x) _pclose(x)
+#define access(x, y) _access(x, y)
+#define getcwd(x, y) _getcwd(x, y)
+
+#ifdef HAVE_STRTOUI64
+#define strtoull(x, y, z) _strtoui64(x, y, z)
+#else
+#define strtoull(x, y, z) strtoul(x, y, z)
+#endif /* HAVE_STRTOUI64 */
+
+#define write(x, y, z) _write(x, y, (unsigned) z)
+#define read(x, y, z) _read(x, y, (unsigned) z)
+#define open(x, y, z) _open(x, y, z)
+#define lseek(x, y, z) _lseek(x, y, z)
+#define close(x) _close(x)
+
+#if !defined(fileno)
+#define fileno(x) _fileno(x)
+#endif /* !fileno MINGW #defines fileno */
+
+typedef HANDLE pthread_mutex_t;
+
+#if !defined(S_ISDIR)
+#define S_ISDIR(x) ((x) & _S_IFDIR)
+#endif /* S_ISDIR */
+
+#if defined(HAVE_STDINT)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned __int64 uint64_t;
+#endif /* HAVE_STDINT */
+
+/*
+ * POSIX dirent interface
+ */
+struct dirent {
+ char d_name[FILENAME_MAX];
+};
+
+typedef struct DIR {
+ HANDLE handle;
+ WIN32_FIND_DATAW info;
+ struct dirent result;
+} DIR;
+
+#else /* UNIX specific */
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+
+#include <pwd.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#define SSL_LIB "libssl.so"
+#define DIRSEP '/'
+#define IS_DIRSEP_CHAR(c) ((c) == '/')
+#define O_BINARY 0
+#define closesocket(a) close(a)
+#define mg_mkdir(x, y) mkdir(x, y)
+#define mg_open(x, y, z) open(x, y, z)
+#define mg_remove(x) remove(x)
+#define mg_stat(x, y) stat(x, y)
+#define ERRNO errno
+#define INVALID_SOCKET (-1)
+typedef int SOCKET;
+
+#endif /* End of Windows and UNIX specific includes */
+
+#include "mongoose.h"
+
+#define MONGOOSE_VERSION "2.4"
+#define PASSWORDS_FILE_NAME ".htpasswd"
+#define CGI_ENVIRONMENT_SIZE 4096
+#define MAX_CGI_ENVIR_VARS 64
+#define MAX_REQUEST_SIZE 16384
+#define MAX_LISTENING_SOCKETS 10
+#define MAX_CALLBACKS 20
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+#define UNKNOWN_CONTENT_LENGTH ((uint64_t) ~0ULL)
+
+/*
+ * Darwin prior to 7.0 and Win32 do not have socklen_t
+ */
+#ifdef NO_SOCKLEN_T
+typedef int socklen_t;
+#endif /* NO_SOCKLEN_T */
+
+#if !defined(FALSE)
+enum {FALSE, TRUE};
+#endif /* !FALSE */
+
+typedef int bool_t;
+typedef void * (*mg_thread_func_t)(void *);
+static void cry(const char *, ...);
+
+static int tz_offset;
+static const char *http_500_error = "Internal Server Error";
+static FILE *error_log;
+
+/*
+ * Snatched from OpenSSL includes. I put the prototypes here to be independent
+ * from the OpenSSL source installation. Having this, mongoose + SSL can be
+ * built on any system with binary SSL libraries installed.
+ */
+typedef struct ssl_st SSL;
+typedef struct ssl_method_st SSL_METHOD;
+typedef struct ssl_ctx_st SSL_CTX;
+
+#define SSL_ERROR_WANT_READ 2
+#define SSL_ERROR_WANT_WRITE 3
+#define SSL_FILETYPE_PEM 1
+
+/*
+ * Dynamically loaded SSL functionality
+ */
+struct ssl_func {
+ const char *name; /* SSL function name */
+ void (*ptr)(void); /* Function pointer */
+};
+
+#define FUNC(x) ssl_sw[x].ptr
+
+#define SSL_free(x) (* (void (*)(SSL *)) FUNC(0))(x)
+#define SSL_accept(x) (* (int (*)(SSL *)) FUNC(1))(x)
+#define SSL_connect(x) (* (int (*)(SSL *)) FUNC(2))(x)
+#define SSL_read(x,y,z) (* (int (*)(SSL *, void *, int)) FUNC(3))((x),(y),(z))
+#define SSL_write(x,y,z) \
+ (* (int (*)(SSL *, const void *,int)) FUNC(4))((x), (y), (z))
+#define SSL_get_error(x,y)(* (int (*)(SSL *, int)) FUNC(5))((x), (y))
+#define SSL_set_fd(x,y) (* (int (*)(SSL *, SOCKET)) FUNC(6))((x), (y))
+#define SSL_new(x) (* (SSL * (*)(SSL_CTX *)) FUNC(7))(x)
+#define SSL_CTX_new(x) (* (SSL_CTX * (*)(SSL_METHOD *)) FUNC(8))(x)
+#define SSLv23_server_method() (* (SSL_METHOD * (*)(void)) FUNC(9))()
+#define SSL_library_init() (* (int (*)(void)) FUNC(10))()
+#define SSL_CTX_use_PrivateKey_file(x,y,z) (* (int (*)(SSL_CTX *, \
+ const char *, int)) FUNC(11))((x), (y), (z))
+#define SSL_CTX_use_certificate_file(x,y,z) (* (int (*)(SSL_CTX *, \
+ const char *, int)) FUNC(12))((x), (y), (z))
+#define SSL_CTX_set_default_passwd_cb(x,y) \
+ (* (void (*)(SSL_CTX *, mg_spcb_t))FUNC(13))((x),(y))
+
+static struct ssl_func ssl_sw[] = {
+ {"SSL_free", NULL},
+ {"SSL_accept", NULL},
+ {"SSL_connect", NULL},
+ {"SSL_read", NULL},
+ {"SSL_write", NULL},
+ {"SSL_get_error", NULL},
+ {"SSL_set_fd", NULL},
+ {"SSL_new", NULL},
+ {"SSL_CTX_new", NULL},
+ {"SSLv23_server_method", NULL},
+ {"SSL_library_init", NULL},
+ {"SSL_CTX_use_PrivateKey_file", NULL},
+ {"SSL_CTX_use_certificate_file",NULL},
+ {"SSL_CTX_set_default_passwd_cb",NULL},
+ {NULL, NULL}
+};
+
+struct usa {
+ socklen_t len;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ } u;
+};
+
+/*
+ * Numeric indexes for the option values in context, ctx->options
+ */
+enum mg_option_index {
+ OPT_ROOT, OPT_INDEX_FILES, OPT_PORTS, OPT_DIR_LIST, OPT_CGI_EXTENSIONS,
+ OPT_CGI_INTERPRETER, OPT_SSI_EXTENSIONS, OPT_AUTH_DOMAIN,
+ OPT_AUTH_GPASSWD, OPT_AUTH_PUT, OPT_ACCESS_LOG, OPT_ERROR_LOG,
+ OPT_SSL_CERTIFICATE, OPT_ALIASES, OPT_ACL, OPT_UID,
+ OPT_PROTECT, OPT_SERVICE, OPT_HIDE, OPT_ADMIN_URI, OPT_THREADS,
+ NUM_OPTIONS
+};
+
+struct socket {
+ SOCKET sock; /* Listening socket */
+ int is_ssl; /* Should be SSL-ed */
+ struct usa usa; /* Socket address */
+};
+
+/*
+ * Callback function, and where it is bound to
+ */
+struct callback {
+ char *uri_regex; /* URI regex to handle */
+ mg_callback_t func; /* user callback */
+ bool_t is_auth; /* func is auth checker */
+ int status_code; /* error code to handle */
+ void *user_data; /* opaque user data */
+};
+
+/*
+ * Socket pool.
+ * Master thread to enqueue accepted sockets by means of put_socket() function.
+ * Worker threads grab sockets from the queue using get_socket() function.
+ */
+struct socket_pool {
+ struct socket sockets[20]; /* Array of sockets to process */
+
+ int size; /* Ringbuffer pointers */
+ int head;
+ int tail;
+
+ pthread_mutex_t mutex;
+ pthread_cond_t put_cond;
+ pthread_cond_t get_cond;
+};
+
+/*
+ * Mongoose context
+ */
+struct mg_context {
+ int stop_flag; /* Should we stop event loop */
+ SSL_CTX *ssl_ctx; /* SSL context */
+
+ FILE *access_log; /* Opened access log */
+ FILE *error_log; /* Opened error log */
+
+ struct socket listeners[MAX_LISTENING_SOCKETS];
+ int num_listeners;
+
+ struct callback callbacks[MAX_CALLBACKS];
+ int num_callbacks;
+
+ char *options[NUM_OPTIONS]; /* Configured opions */
+ pthread_mutex_t mutex; /* Option setter/getter guard */
+ struct socket_pool socket_pool; /* Socket pool */
+
+ mg_spcb_t ssl_password_callback;
+};
+
+struct mg_connection {
+ struct mg_request_info request_info;
+ struct mg_context *ctx; /* Mongoose context we belong to*/
+ SSL *ssl; /* SSL descriptor */
+ SOCKET sock; /* Connected socket */
+ struct usa rsa; /* Remote socket address */
+ struct usa lsa; /* Local socket address */
+ time_t birth_time; /* Time connection was accepted */
+ bool_t free_post_data; /* post_data was malloc-ed */
+ bool_t keep_alive; /* Keep-Alive flag */
+ uint64_t num_bytes_sent; /* Total bytes sent to client */
+};
+
+/*
+ * In Mongoose, list of values are represented as comma separated
+ * string. For example, list of CGI extensions can be represented as
+ * ".cgi,.php,.pl", FOR_EACH_WORD_IN_LIST macro allows to
+ * loop through the individual values in that list.
+ *
+ * A "const char *" and "int" variables must be passed to the macro.
+ *
+ * In every iteration of the loop, "s" points to the current value, and
+ * "len" specifies its length. Code inside loop must not change "s" and "len".
+ */
+#define FOR_EACH_WORD_IN_LIST(s, len) \
+ for (; s != NULL && (len = strcspn(s, ",")) != 0; \
+ s += len, s+= strspn(s, ","))
+
+/*
+ * Print error message to the opened error log stream.
+ */
+static void
+cry(const char *fmt, ...)
+{
+ FILE *fp;
+ va_list ap;
+
+ fp = error_log == NULL ? stderr : error_log;
+ va_start(ap, fmt);
+ (void) vfprintf(fp, fmt, ap);
+ va_end(ap);
+
+ fputc('\n', fp);
+}
+
+const char *
+mg_version(void)
+{
+ return (MONGOOSE_VERSION);
+}
+
+static void
+mg_strlcpy(register char *dst, register const char *src, size_t n)
+{
+ for (; *src != '\0' && n > 1; n--)
+ *dst++ = *src++;
+ *dst = '\0';
+}
+
+static int
+mg_strncasecmp(const char *str1, const char *str2, size_t len)
+{
+ const unsigned char *s1, *s2, *end;
+
+ s1 = (unsigned char *) str1;
+ s2 = (unsigned char *) str2;
+ end = s1 + len - 1;
+
+ while (s1 < end && *s1 && *s2 && tolower(*s1) == tolower(*s2)) {
+ s1++;
+ s2++;
+ }
+
+ return (tolower(*s1) - tolower(*s2));
+}
+
+static int
+mg_strcasecmp(const char *str1, const char *str2)
+{
+ size_t len = strlen(str1);
+ int res = mg_strncasecmp(str1, str2, len);
+
+ if (res != 0)
+ return (res);
+ else
+ return (-str2[len]); /* If str2[len] == 0, -0 == 0. */
+}
+
+static char *
+mg_strndup(const char *ptr, size_t len)
+{
+ char *p;
+
+ if ((p = (char *) malloc(len + 1)) != NULL)
+ mg_strlcpy(p, ptr, len + 1);
+
+ return (p);
+
+}
+
+static char *
+mg_strdup(const char *str)
+{
+ return (mg_strndup(str, strlen(str)));
+}
+
+/*
+ * Like snprintf(), but never returns negative value, or the value
+ * that is larger than a supplied buffer.
+ * Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
+ * in his audit report.
+ */
+static int
+mg_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap)
+{
+ int n;
+
+ if (buflen == 0)
+ return (0);
+
+ n = vsnprintf(buf, buflen, fmt, ap);
+
+ if (n < 0) {
+ cry("vsnprintf error");
+ n = 0;
+ } else if (n >= (int) buflen) {
+ cry("truncating vsnprintf buffer");
+ n = (int) buflen - 1;
+ }
+ buf[n] = '\0';
+
+ return (n);
+}
+
+static int
+mg_snprintf(char *buf, size_t buflen, const char *fmt, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = mg_vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+
+ return (n);
+}
+
+static int
+get_pool_space(const struct socket_pool *pool)
+{
+ return (pool->size - (pool->head - pool->tail));
+}
+
+static void
+init_socket_pool(struct socket_pool *pool)
+{
+ pool->size = (int) ARRAY_SIZE(pool->sockets) - 1;
+ pool->head = pool->tail = 0;
+
+ (void) pthread_mutex_init(&pool->mutex, NULL);
+ (void) pthread_cond_init(&pool->put_cond, NULL);
+ (void) pthread_cond_init(&pool->get_cond, NULL);
+}
+
+static void
+destroy_socket_pool(struct socket_pool *pool)
+{
+ int i;
+
+ (void) pthread_mutex_destroy(&pool->mutex);
+ (void) pthread_cond_destroy(&pool->put_cond);
+ (void) pthread_cond_destroy(&pool->get_cond);
+
+ /* TODO: close sockets */
+ for (i = 0; i < get_pool_space(pool); i++)
+ (void) closesocket(pool->sockets[i].sock);
+}
+
+/*
+ * Put socket into the pool
+ */
+static void
+put_socket(struct socket_pool *pool, const struct socket *sp)
+{
+ (void) pthread_mutex_lock(&pool->mutex);
+
+ while (get_pool_space(pool) == 0)
+ (void) pthread_cond_wait(&pool->put_cond, &pool->mutex);
+
+ pool->sockets[pool->head++ % pool->size] = *sp;
+
+ (void) pthread_cond_signal(&pool->get_cond);
+ (void) pthread_mutex_unlock(&pool->mutex);
+}
+
+/*
+ * Get index of the socket to process
+ */
+static void
+get_socket(struct socket_pool *pool, struct socket *sp)
+{
+ pthread_mutex_lock(&pool->mutex);
+
+ while (get_pool_space(pool) == pool->size)
+ (void) pthread_cond_wait(&pool->get_cond, &pool->mutex);
+
+ *sp = pool->sockets[pool->tail++ % pool->size];
+
+ assert(pool->tail <= pool->head);
+
+ /* Wrap pointers if they both are greater than the pool size */
+ if (pool->tail > pool->size) {
+ pool->tail %= pool->size;
+ pool->head %= pool->size;
+ }
+
+ pthread_cond_signal(&pool->put_cond);
+ pthread_mutex_unlock(&pool->mutex);
+}
+
+/*
+ * Convert string representing a boolean value to a boolean value
+ */
+static bool_t
+is_true(const char *str)
+{
+ static const char *trues[] = {"1", "yes", "true", "jawohl", NULL};
+ const char **p;
+
+ for (p = trues; *p != NULL; p++)
+ if (str && !mg_strcasecmp(str, *p))
+ return (TRUE);
+
+ return (FALSE);
+}
+
+/*
+ * Skip the characters until one of the delimiters characters found.
+ * 0-terminate resulting word. Skip the rest of the delimiters if any.
+ * Advance pointer to buffer to the next word. Return found 0-terminated word.
+ */
+static char *
+skip(char **buf, const char *delimiters)
+{
+ char *p, *begin_word, *end_word, *end_delimiters;
+
+ begin_word = *buf;
+ end_word = begin_word + strcspn(begin_word, delimiters);
+ end_delimiters = end_word + strspn(end_word, delimiters);
+
+ for (p = end_word; p < end_delimiters; p++)
+ *p = '\0';
+
+ *buf = end_delimiters;
+
+ return (begin_word);
+}
+
+/*
+ * Return HTTP header value, or NULL if not found.
+ */
+static const char *
+get_header(const struct mg_request_info *ri, const char *name)
+{
+ int i;
+
+ for (i = 0; i < ri->num_headers; i++)
+ if (!mg_strcasecmp(name, ri->http_headers[i].name))
+ return (ri->http_headers[i].value);
+
+ return (NULL);
+}
+
+const char *
+mg_get_header(const struct mg_connection *conn, const char *name)
+{
+ return (get_header(&conn->request_info, name));
+}
+
+#if !(defined(NO_CGI) && defined(NO_SSI))
+/*
+ * Verify that given file has certain extension
+ */
+static bool_t
+match_extension(const char *path, const char *ext_list)
+{
+ size_t len, path_len;
+
+ path_len = strlen(path);
+
+ FOR_EACH_WORD_IN_LIST(ext_list, len)
+ if (len < path_len && path[path_len - (len + 1)] == '.' &&
+ !mg_strncasecmp(path + path_len - len, ext_list, len))
+ return (TRUE);
+
+ return (FALSE);
+}
+#endif /* !(NO_CGI && NO_SSI) */
+
+static bool_t
+match_regex(const char *uri, const char *regexp)
+{
+ if (*regexp == '\0')
+ return (*uri == '\0');
+
+ if (*regexp == '*')
+ do {
+ if (match_regex(uri, regexp + 1))
+ return (TRUE);
+ } while (*uri++ != '\0');
+
+ if (*uri != '\0' && *regexp == *uri)
+ return (match_regex(uri + 1, regexp + 1));
+
+ return (FALSE);
+}
+
+static const struct callback *
+find_callback(const struct mg_context *ctx, bool_t is_auth,
+ const char *uri, int status_code)
+{
+ const struct callback *cb;
+ int i;
+
+ for (i = 0; i < ctx->num_callbacks; i++) {
+ cb = ctx->callbacks + i;
+ if ((uri != NULL && cb->uri_regex != NULL &&
+ ((is_auth && cb->is_auth) || (!is_auth && !cb->is_auth)) &&
+ match_regex(uri, cb->uri_regex)) || (uri == NULL &&
+ (cb->status_code == 0 || cb->status_code == status_code)))
+ return (cb);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Send error message back to a client.
+ */
+static void
+send_error(struct mg_connection *conn, int status, const char *reason,
+ const char *fmt, ...)
+{
+ const struct callback *cb;
+ char buf[BUFSIZ];
+ va_list ap;
+ int len;
+
+ conn->request_info.status_code = status;
+
+ /* If error handler is set, call it. Otherwise, send error message */
+ if ((cb = find_callback(conn->ctx, FALSE, NULL, status)) != NULL) {
+ cb->func(conn, &conn->request_info, cb->user_data);
+ } else {
+ (void) mg_printf(conn,
+ "HTTP/1.1 %d %s\r\n"
+ "Content-Type: text/plain\r\n"
+ "Connection: close\r\n"
+ "\r\n", status, reason);
+
+ /* Errors 1xx, 204 and 304 MUST NOT send a body */
+ if (status > 199 && status != 204 && status != 304) {
+ conn->num_bytes_sent = mg_printf(conn,
+ "Error %d: %s\n", status, reason);
+
+ va_start(ap, fmt);
+ len = mg_vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ conn->num_bytes_sent += mg_write(conn, buf, len);
+ }
+ }
+}
+
+#ifdef _WIN32
+static int
+pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
+ unused = NULL;
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ return (*mutex == NULL ? -1 : 0);
+}
+
+static int
+pthread_mutex_destroy(pthread_mutex_t *mutex) {
+ CloseHandle(*mutex);
+ return (0);
+}
+
+static int
+pthread_mutex_lock(pthread_mutex_t *mutex) {
+ return (WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1);
+}
+
+static int
+pthread_mutex_unlock(pthread_mutex_t *mutex) {
+ return (ReleaseMutex(*mutex) == 0 ? -1 : 0);
+}
+
+static void
+fix_directory_separators(char *path)
+{
+ for (; *path != '\0'; path++) {
+ if (*path == '/')
+ *path = '\\';
+ if (*path == '\\')
+ while (path[1] == '\\' || path[1] == '/')
+ (void) memmove(path + 1,
+ path + 2, strlen(path + 2) + 1);
+ }
+}
+
+static void
+to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len)
+{
+ char buf[FILENAME_MAX], *p;
+
+ mg_strlcpy(buf, path, sizeof(buf));
+ fix_directory_separators(buf);
+
+ /* Point p to the end of the file name */
+ p = buf + strlen(buf) - 1;
+
+ /* Trim trailing backslash character */
+ while (p > buf && *p == '\\' && p[-1] != ':')
+ *p-- = '\0';
+
+ /*
+ * Protect from CGI code disclosure.
+ * This is very nasty hole. Windows happily opens files with
+ * some garbage in the end of file name. So fopen("a.cgi ", "r")
+ * actually opens "a.cgi", and does not return an error!
+ */
+ if (*p == 0x20 || *p == 0x2e || *p == 0x2b || (*p & ~0x7f)) {
+ cry("Rejecting suspicious path: [%s]", buf);
+ buf[0] = '\0';
+ }
+
+ MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
+}
+
+static int
+mg_open(const char *path, int flags, int mode)
+{
+ wchar_t wbuf[FILENAME_MAX];
+
+ to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
+
+ return (_wopen(wbuf, flags, mode));
+}
+
+static int
+mg_stat(const char *path, struct stat *stp)
+{
+ wchar_t wbuf[FILENAME_MAX];
+
+ to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
+
+ return (_wstat(wbuf, (struct _stat *) stp));
+}
+
+static int
+mg_remove(const char *path)
+{
+ wchar_t wbuf[FILENAME_MAX];
+
+ to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
+
+ return (_wremove(wbuf));
+}
+
+static DIR *
+opendir(const char *name)
+{
+ DIR *dir = NULL;
+ char path[FILENAME_MAX];
+ wchar_t wpath[FILENAME_MAX];
+
+ if (name == NULL || name[0] == '\0') {
+ errno = EINVAL;
+ } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
+ errno = ENOMEM;
+ } else {
+ mg_snprintf(path, sizeof(path), "%s/*", name);
+ to_unicode(path, wpath, ARRAY_SIZE(wpath));
+ dir->handle = FindFirstFileW(wpath, &dir->info);
+
+ if (dir->handle != INVALID_HANDLE_VALUE) {
+ dir->result.d_name[0] = '\0';
+ } else {
+ free(dir);
+ dir = NULL;
+ }
+ }
+
+ return (dir);
+}
+
+static int
+closedir(DIR *dir)
+{
+ int result = -1;
+
+ if (dir != NULL) {
+ if (dir->handle != INVALID_HANDLE_VALUE)
+ result = FindClose(dir->handle) ? 0 : -1;
+
+ free(dir);
+ }
+
+ if (result == -1)
+ errno = EBADF;
+
+ return (result);
+}
+
+struct dirent *
+readdir(DIR *dir)
+{
+ struct dirent *result = 0;
+
+ if (dir && dir->handle != INVALID_HANDLE_VALUE) {
+ if(!dir->result.d_name ||
+ FindNextFileW(dir->handle, &dir->info)) {
+ result = &dir->result;
+
+ WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName,
+ -1, result->d_name,
+ sizeof(result->d_name), NULL, NULL);
+ }
+ } else {
+ errno = EBADF;
+ }
+
+ return (result);
+}
+
+#define set_close_on_exec(fd) /* No FD_CLOEXEC on Windows */
+
+static int
+start_thread(void * (*func)(void *), void *param)
+{
+ return (_beginthread((void (__cdecl *)( void *))func, 0, param) == 0);
+}
+
+static bool_t
+spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
+ char *envp[], int fd_stdin, int fd_stdout, const char *dir)
+{
+ HANDLE me;
+ char *p, *interp, cmdline[FILENAME_MAX], line[FILENAME_MAX];
+ FILE *fp;
+ bool_t retval;
+ STARTUPINFOA si;
+ PROCESS_INFORMATION pi;
+
+ envp = NULL; /* Unused */
+
+ (void) memset(&si, 0, sizeof(si));
+ (void) memset(&pi, 0, sizeof(pi));
+
+ /* XXX redirect CGI errors to the error log file */
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ me = GetCurrentProcess();
+ DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
+ &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
+ DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
+ &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
+
+ /* If CGI file is a script, try to read the interpreter line */
+ interp = conn->ctx->options[OPT_CGI_INTERPRETER];
+ if (interp == NULL) {
+ line[2] = '\0';
+ (void) mg_snprintf(cmdline, sizeof(cmdline), "%s%c%s",
+ dir, DIRSEP, prog);
+ if ((fp = fopen(cmdline, "r")) != NULL) {
+ (void) fgets(line, sizeof(line), fp);
+ if (memcmp(line, "#!", 2) != 0)
+ line[2] = '\0';
+ /* Trim whitespaces from interpreter name */
+ for (p = &line[strlen(line) - 1]; p > line &&
+ isspace(*p); p--)
+ *p = '\0';
+ (void) fclose(fp);
+ }
+ interp = line + 2;
+ (void) mg_snprintf(cmdline, sizeof(cmdline), "%s%s%s",
+ line + 2, line[2] == '\0' ? "" : " ", prog);
+ }
+
+ if ((p = (char *) strrchr(prog, '/')) != NULL)
+ prog = p + 1;
+
+ (void) mg_snprintf(cmdline, sizeof(cmdline), "%s %s", interp, prog);
+ (void) mg_snprintf(line, sizeof(line), "%s", dir);
+ fix_directory_separators(line);
+ fix_directory_separators(cmdline);
+
+ if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
+ CREATE_NEW_PROCESS_GROUP, envblk, line, &si, &pi) == 0) {
+ cry("%s: CreateProcess(%s): %d", __func__, cmdline, ERRNO);
+ retval = FALSE;
+ } else {
+ close(fd_stdin);
+ close(fd_stdout);
+ retval = TRUE;
+ }
+
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdInput);
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+
+ return (retval);
+}
+
+static int
+pipe(int *fds)
+{
+ return (_pipe(fds, BUFSIZ, _O_BINARY));
+}
+
+static int
+mg_mkdir(const char *path, int mode)
+{
+ char buf[FILENAME_MAX];
+ wchar_t wbuf[FILENAME_MAX];
+
+ mode = 0; /* Unused */
+ mg_strlcpy(buf, path, sizeof(buf));
+ fix_directory_separators(buf);
+
+ MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
+
+ return (_wmkdir(wbuf));
+}
+
+#else
+
+static void
+set_close_on_exec(int fd)
+{
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+static int
+start_thread(void * (*func)(void *), void *param)
+{
+ pthread_t thread_id;
+ pthread_attr_t attr;
+ int retval;
+
+ (void) pthread_attr_init(&attr);
+ (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0)
+ cry("%s: %s", __func__, strerror(retval));
+
+ return (retval);
+}
+
+#ifndef NO_CGI
+static bool_t
+spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
+ char *envp[], int fd_stdin, int fd_stdout, const char *dir)
+{
+ int ret;
+ pid_t pid;
+ const char *interp;
+
+ envblk = NULL; /* unused */
+ ret = FALSE;
+
+ if ((pid = fork()) == -1) {
+ /* Parent */
+ ret = -1;
+ send_error(conn, 500, http_500_error,
+ "fork(): %s", strerror(ERRNO));
+ } else if (pid == 0) {
+ /* Child */
+ if (chdir(dir) != 0) {
+ cry("chdir(%s): %s", dir, strerror(ERRNO));
+ } else if (dup2(fd_stdin, 0) == -1) {
+ cry("dup2(stdin, %d): %s", fd_stdin, strerror(ERRNO));
+ } else if (dup2(fd_stdout, 1) == -1) {
+ cry("dup2(stdout, %d): %s", fd_stdout, strerror(ERRNO));
+ } else {
+ /* If error file is specified, send errors there */
+ if (error_log != NULL)
+ (void) dup2(fileno(error_log), 2);
+
+ (void) close(fd_stdin);
+ (void) close(fd_stdout);
+
+ /* Execute CGI program */
+ interp = conn->ctx->options[OPT_CGI_INTERPRETER];
+ if (interp == NULL) {
+ (void) execle(prog, prog, NULL, envp);
+ cry("execle(%s): %s", prog, strerror(ERRNO));
+ } else {
+ (void) execle(interp, interp, prog, NULL, envp);
+ cry("execle(%s %s): %s",
+ interp, prog, strerror(ERRNO));
+ }
+ }
+ exit(EXIT_FAILURE);
+ } else {
+ /* Parent. Suspended until child does execle() */
+ (void) close(fd_stdin);
+ (void) close(fd_stdout);
+ ret = TRUE;
+ }
+
+ return (ret);
+}
+#endif /* !NO_CGI */
+#endif /* _WIN32 */
+
+static void
+mg_lock(struct mg_context *ctx)
+{
+ if (pthread_mutex_lock(&ctx->mutex) != 0)
+ cry("pthread_mutex_lock: %s", strerror(ERRNO));
+}
+
+static void
+mg_unlock(struct mg_context *ctx)
+{
+ if (pthread_mutex_unlock(&ctx->mutex) != 0)
+ cry("pthread_mutex_unlock: %s", strerror(ERRNO));
+}
+
+/*
+ * Write data to the IO channel - opened file descriptor, socket or SSL
+ * descriptor. Return number of bytes written.
+ */
+static uint64_t
+push(int fd, SOCKET sock, SSL *ssl, const char *buf, uint64_t len)
+{
+ uint64_t sent;
+ int n, k;
+
+ sent = 0;
+ while (sent < len) {
+
+ /* How many bytes we send in this iteration */
+ k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
+
+ if (ssl != NULL) {
+ n = SSL_write(ssl, buf + sent, k);
+ } else if (fd != -1) {
+ n = write(fd, buf + sent, k);
+ } else {
+ n = send(sock, buf + sent, k, 0);
+ }
+
+ if (n < 0) {
+ cry("%s: %s", __func__, strerror(ERRNO));
+ break;
+ } else {
+ sent += n;
+ }
+ }
+
+ return (sent);
+}
+
+/*
+ * Read from IO channel - opened file descriptor, socket, or SSL descriptor.
+ * Return number of bytes read.
+ */
+static int
+pull(int fd, SOCKET sock, SSL *ssl, char *buf, int len)
+{
+ int nread;
+
+ if (ssl != NULL) {
+ nread = SSL_read(ssl, buf, len);
+ } else if (fd != -1) {
+ nread = read(fd, buf, (size_t) len);
+ } else {
+ nread = recv(sock, buf, (size_t) len, 0);
+ }
+
+ if (nread < 0)
+ cry("%s failed: %s", __func__, strerror(ERRNO));
+
+ return (nread);
+}
+
+int
+mg_write(struct mg_connection *conn, const void *buf, int len)
+{
+ assert(len >= 0);
+ return ((int) push(-1, conn->sock, conn->ssl,
+ (const char *) buf, (uint64_t) len));
+}
+
+int
+mg_printf(struct mg_connection *conn, const char *fmt, ...)
+{
+ char buf[MAX_REQUEST_SIZE];
+ int len;
+ va_list ap;
+
+ va_start(ap, fmt);
+ len = mg_vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ return (mg_write(conn, buf, len));
+}
+
+/*
+ * Return content length of the request, or UNKNOWN_CONTENT_LENGTH constant if
+ * Content-Length header is not set.
+ */
+static uint64_t
+get_content_length(const struct mg_connection *conn)
+{
+ const char *cl = mg_get_header(conn, "Content-Length");
+ return (cl == NULL ? UNKNOWN_CONTENT_LENGTH : strtoull(cl, NULL, 10));
+}
+
+/*
+ * URL-decode input buffer into destination buffer.
+ * 0-terminate the destination buffer. Return the length of decoded data.
+ * form-url-encoded data differs from URI encoding in a way that it
+ * uses '+' as character for space, see RFC 1866 section 8.2.1
+ * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
+ */
+static size_t
+url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
+ bool_t is_form_url_encoded)
+{
+ size_t i, j;
+ int a, b;
+#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
+
+ for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
+ if (src[i] == '%' &&
+ isxdigit(* (unsigned char *) (src + i + 1)) &&
+ isxdigit(* (unsigned char *) (src + i + 2))) {
+ a = tolower(* (unsigned char *) (src + i + 1));
+ b = tolower(* (unsigned char *) (src + i + 2));
+ dst[j] = ((HEXTOI(a) << 4) | HEXTOI(b)) & 0xff;
+ i += 2;
+ } else if (is_form_url_encoded && src[i] == '+') {
+ dst[j] = ' ';
+ } else {
+ dst[j] = src[i];
+ }
+ }
+
+ dst[j] = '\0'; /* Null-terminate the destination */
+
+ return (j);
+}
+
+/*
+ * Search for a form variable in a given buffer.
+ * Semantic is the same as for mg_get_var().
+ */
+static char *
+get_var(const char *name, const char *buf, size_t buf_len)
+{
+ const char *p, *e, *s;
+ char tmp[BUFSIZ];
+ size_t var_len;
+
+ var_len = strlen(name);
+ e = buf + buf_len;
+
+ /* buf is "var1=val1&var2=val2...". Find variable first */
+ for (p = buf; p + var_len < e; p++)
+ if ((p == buf || p[-1] == '&') && p[var_len] == '=' &&
+ !mg_strncasecmp(name, p, var_len)) {
+
+ /* Point p to variable value */
+ p += var_len + 1;
+
+ /* Point s to the end of the value */
+ s = (const char *) memchr(p, '&', e - p);
+ if (s == NULL)
+ s = e;
+
+ /* URL-decode value. Return result length */
+ (void) url_decode(p, s - p, tmp, sizeof(tmp), TRUE);
+ return (mg_strdup(tmp));
+ }
+
+ return (NULL);
+}
+
+/*
+ * Return form data variable.
+ * It can be specified in query string, or in the POST data.
+ * Return NULL if the variable not found, or allocated 0-terminated value.
+ * It is caller's responsibility to free the returned value.
+ */
+char *
+mg_get_var(const struct mg_connection *conn, const char *name)
+{
+ const struct mg_request_info *ri = &conn->request_info;
+ char *v1, *v2;
+
+ v1 = v2 = NULL;
+
+ /* Look in both query_string and POST data */
+ if (ri->query_string != NULL)
+ v1 = get_var(name, ri->query_string, strlen(ri->query_string));
+ if (ri->post_data_len > 0)
+ v2 = get_var(name, ri->post_data, ri->post_data_len);
+
+ /* If they both have queried variable, POST data wins */
+ if (v1 != NULL && v2 != NULL)
+ free(v1);
+
+ return (v2 == NULL ? v1 : v2);
+}
+
+/*
+ * Transform URI to the file name.
+ */
+static void
+make_path(struct mg_context *ctx, const char *uri, char *buf, size_t buf_len)
+{
+ char *p, *s;
+ size_t len;
+
+ mg_snprintf(buf, buf_len, "%s%s", ctx->options[OPT_ROOT], uri);
+
+ /* If requested URI has aliased prefix, use alternate root */
+ mg_lock(ctx);
+ s = ctx->options[OPT_ALIASES];
+ FOR_EACH_WORD_IN_LIST(s, len) {
+
+ p = (char *) memchr(s, '=', len);
+ if (p == NULL || p >= s + len || p == s)
+ continue;
+
+ if (memcmp(uri, s, p - s) == 0) {
+ (void) mg_snprintf(buf, buf_len, "%.*s%s",
+ (s + len) - p - 1, p + 1, uri + (p - s));
+ break;
+ }
+ }
+ mg_unlock(ctx);
+
+ /* Remove trailing '/' characters, if directory is requested */
+ for (p = buf + strlen(buf) - 1; p > buf && *p == '/'; p--)
+ *p = '\0';
+
+#ifdef _WIN32
+ for (p = buf; *p != '\0'; p++)
+ if (*p == '/')
+ *p = '\\';
+#endif /* _WIN32 */
+}
+
+/*
+ * Setup listening socket on given port, return socket
+ */
+static SOCKET
+mg_open_listening_port(int port)
+{
+ SOCKET sock;
+ int on = 1;
+ struct usa sa;
+
+ sa.len = sizeof(sa.u.sin);
+ sa.u.sin.sin_family = AF_INET;
+ sa.u.sin.sin_port = htons((uint16_t) port);
+ sa.u.sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if ((sock = socket(PF_INET, SOCK_STREAM, 6)) != INVALID_SOCKET &&
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &on, sizeof(on)) == 0 &&
+ bind(sock, &sa.u.sa, sa.len) == 0 &&
+ listen(sock, 128) == 0) {
+ /* Success */
+ set_close_on_exec(sock);
+ } else {
+ /* Error */
+ cry("open_listening_port(%d): %s", port, strerror(errno));
+ if (sock != INVALID_SOCKET)
+ (void) closesocket(sock);
+ sock = INVALID_SOCKET;
+ }
+
+ return (sock);
+}
+
+/*
+ * Check whether full request is buffered Return headers length, or 0
+ */
+static int
+get_request_len(const char *buf, size_t buflen)
+{
+ const char *s, *e;
+ int len = 0;
+
+ for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
+ /* Control characters are not allowed but >=128 is. */
+ if (!isprint(* (unsigned char *) s) && *s != '\r' &&
+ *s != '\n' && * (unsigned char *) s < 128)
+ len = -1;
+ else if (s[0] == '\n' && s[1] == '\n')
+ len = (int) (s - buf) + 2;
+ else if (s[0] == '\n' && &s[1] < e &&
+ s[1] == '\r' && s[2] == '\n')
+ len = (int) (s - buf) + 3;
+
+ return (len);
+}
+
+/*
+ * Convert month to the month number. Return -1 on error, or month number
+ */
+static int
+montoi(const char *s)
+{
+ static const char *month_names[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ size_t i;
+
+ for (i = 0; i < sizeof(month_names) / sizeof(month_names[0]); i++)
+ if (!strcmp(s, month_names[i]))
+ return ((int) i);
+
+ return (-1);
+}
+
+/*
+ * Parse date-time string, and return the corresponding time_t value
+ */
+static time_t
+date_to_epoch(const char *s)
+{
+ struct tm tm, *tmp;
+ time_t current_time;
+ char mon[32];
+ int sec, min, hour, mday, month, year;
+
+ (void) memset(&tm, 0, sizeof(tm));
+ sec = min = hour = mday = month = year = 0;
+
+ if (((sscanf(s, "%d/%3s/%d %d:%d:%d",
+ &mday, mon, &year, &hour, &min, &sec) == 6) ||
+ (sscanf(s, "%d %3s %d %d:%d:%d",
+ &mday, mon, &year, &hour, &min, &sec) == 6) ||
+ (sscanf(s, "%*3s, %d %3s %d %d:%d:%d",
+ &mday, mon, &year, &hour, &min, &sec) == 6) ||
+ (sscanf(s, "%d-%3s-%d %d:%d:%d",
+ &mday, mon, &year, &hour, &min, &sec) == 6)) &&
+ (month = montoi(mon)) != -1) {
+ tm.tm_mday = mday;
+ tm.tm_mon = month;
+ tm.tm_year = year;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+ }
+
+ if (tm.tm_year > 1900)
+ tm.tm_year -= 1900;
+ else if (tm.tm_year < 70)
+ tm.tm_year += 100;
+
+ /* Set Daylight Saving Time field */
+ current_time = time(NULL);
+ tmp = localtime(¤t_time);
+ tm.tm_isdst = tmp->tm_isdst;
+
+ return (mktime(&tm));
+}
+
+static void
+remove_double_dots(char *s)
+{
+ char *p = s;
+
+ while (*s != '\0') {
+ *p++ = *s++;
+ if (s[-1] == '/' || s[-1] == '\\')
+ while (*s == '.' || *s == '/' || *s == '\\')
+ s++;
+ }
+ *p = '\0';
+}
+
+static const struct {
+ const char *extension;
+ const char *mime_type;
+} mime_types[] = {
+ {"html", "text/html" },
+ {"htm", "text/html" },
+ {"shtm", "text/html" },
+ {"shtml", "text/html" },
+ {"css", "text/css" },
+ {"js", "application/x-javascript" },
+ {"ico", "image/x-icon" },
+ {"gif", "image/gif" },
+ {"jpg", "image/jpeg" },
+ {"jpeg", "image/jpeg" },
+ {"png", "image/png" },
+ {"svg", "image/svg+xml" },
+ {"torrent", "application/x-bittorrent" },
+ {"wav", "audio/x-wav" },
+ {"mp3", "audio/x-mp3" },
+ {"mid", "audio/mid" },
+ {"m3u", "audio/x-mpegurl" },
+ {"ram", "audio/x-pn-realaudio" },
+ {"ra", "audio/x-pn-realaudio" },
+ {"doc", "application/msword", },
+ {"exe", "application/octet-stream" },
+ {"zip", "application/x-zip-compressed" },
+ {"xls", "application/excel" },
+ {"tgz", "application/x-tar-gz" },
+ {"tar.gz", "application/x-tar-gz" },
+ {"tar", "application/x-tar" },
+ {"gz", "application/x-gunzip" },
+ {"arj", "application/x-arj-compressed" },
+ {"rar", "application/x-arj-compressed" },
+ {"rtf", "application/rtf" },
+ {"pdf", "application/pdf" },
+ {"swf", "application/x-shockwave-flash" },
+ {"mpg", "video/mpeg" },
+ {"mpeg", "video/mpeg" },
+ {"asf", "video/x-ms-asf" },
+ {"avi", "video/x-msvideo" },
+ {"bmp", "image/bmp" },
+ {NULL, NULL }
+};
+
+static const char *
+get_mime_type(const char *path)
+{
+ const char *extension;
+ size_t i, ext_len;
+
+ if ((extension = strrchr(path, '.')) != NULL) {
+
+ extension++;
+ ext_len = strlen(extension);
+
+ /* If no luck, try built-in mime types */
+ for (i = 0; mime_types[i].extension != NULL; i++)
+ if (!mg_strcasecmp(extension,
+ mime_types[i].extension))
+ return (mime_types[i].mime_type);
+ }
+
+ return ("text/plain");
+}
+
+#if !defined(NO_AUTH)
+#ifndef HAVE_MD5
+typedef struct MD5Context {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ unsigned char in[64];
+} MD5_CTX;
+
+#if __BYTE_ORDER == 1234
+#define byteReverse(buf, len) /* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void
+byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32_t t;
+ do {
+ t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32_t *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif /* __BYTE_ORDER */
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+static void
+MD5Init(MD5_CTX *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+ register uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void
+MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+static void
+MD5Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+ ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset((char *) ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+#endif /* !HAVE_MD5 */
+
+/*
+ * Stringify binary data. Output buffer must be twice as big as input,
+ * because each byte takes 2 bytes in string representation
+ */
+static void
+bin2str(char *to, const unsigned char *p, size_t len)
+{
+ static const char *hex = "0123456789abcdef";
+
+ for (; len--; p++) {
+ *to++ = hex[p[0] >> 4];
+ *to++ = hex[p[0] & 0x0f];
+ }
+ *to = '\0';
+}
+
+/*
+ * Return stringified MD5 hash for list of vectors.
+ * buf must point to 33-bytes long buffer
+ */
+void
+mg_md5(char *buf, ...)
+{
+ unsigned char hash[16];
+ const char *p;
+ va_list ap;
+ MD5_CTX ctx;
+
+ MD5Init(&ctx);
+
+ va_start(ap, buf);
+ while ((p = va_arg(ap, const char *)) != NULL)
+ MD5Update(&ctx, (unsigned char *) p, (int) strlen(p));
+ va_end(ap);
+
+ MD5Final(hash, &ctx);
+ bin2str(buf, hash, sizeof(hash));
+}
+
+/*
+ * Check the user's password, return 1 if OK
+ */
+static bool_t
+check_password(const char *method, const char *ha1, const char *uri,
+ const char *nonce, const char *nc, const char *cnonce,
+ const char *qop, const char *response)
+{
+ char ha2[32 + 1], expected_response[32 + 1];
+
+ /* XXX Due to a bug in MSIE, we do not compare the URI */
+ /* Also, we do not check for authentication timeout */
+ if (/*strcmp(dig->uri, c->ouri) != 0 || */
+ strlen(response) != 32 /*||
+ now - strtoul(dig->nonce, NULL, 10) > 3600 */)
+ return (FALSE);
+
+ mg_md5(ha2, method, ":", uri, NULL);
+ mg_md5(expected_response, ha1, ":", nonce, ":", nc,
+ ":", cnonce, ":", qop, ":", ha2, NULL);
+
+ return (!mg_strcasecmp(response, expected_response));
+}
+
+/*
+ * Use the global passwords file, if specified by auth_gpass option,
+ * or search for .htpasswd in the requested directory.
+ */
+static FILE *
+open_auth_file(struct mg_context *ctx, const char *path)
+{
+ char name[FILENAME_MAX];
+ const char *p, *e;
+ struct stat st;
+ FILE *fp;
+
+ if (ctx->options[OPT_AUTH_GPASSWD] != NULL) {
+ /* Use global passwords file */
+ if ((fp = fopen(ctx->options[OPT_AUTH_GPASSWD], "r")) == NULL)
+ cry("fopen(%s): %s",
+ ctx->options[OPT_AUTH_GPASSWD], strerror(ERRNO));
+ } else if (!mg_stat(path, &st) && S_ISDIR(st.st_mode)) {
+ (void) mg_snprintf(name, sizeof(name), "%s%c%s",
+ path, DIRSEP, PASSWORDS_FILE_NAME);
+ fp = fopen(name, "r");
+ } else {
+ /*
+ * Try to find .htpasswd in requested directory.
+ * Given the path, create the path to .htpasswd file
+ * in the same directory. Find the right-most
+ * directory separator character first. That would be the
+ * directory name. If directory separator character is not
+ * found, 'e' will point to 'p'.
+ */
+ for (p = path, e = p + strlen(p) - 1; e > p; e--)
+ if (IS_DIRSEP_CHAR(*e))
+ break;
+
+ /*
+ * Make up the path by concatenating directory name and
+ * .htpasswd file name.
+ */
+ (void) mg_snprintf(name, sizeof(name), "%.*s%c%s",
+ (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME);
+ fp = fopen(name, "r");
+ }
+
+ return (fp);
+}
+
+struct ah {
+ char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
+};
+
+static bool_t
+parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size,
+ struct ah *ah)
+{
+ char *name, *value, *s;
+ const char *auth_header;
+
+ if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
+ mg_strncasecmp(auth_header, "Digest ", 7) != 0)
+ return (FALSE);
+
+ /* Make modifiable copy of the auth header */
+ (void) mg_strlcpy(buf, auth_header + 7, buf_size);
+
+ s = buf;
+ (void) memset(ah, 0, sizeof(*ah));
+
+ /* Gobble initial spaces */
+ while (isspace(* (unsigned char *) s))
+ s++;
+
+ /* Parse authorization header */
+ for (;;) {
+ name = skip(&s, "=");
+ value = skip(&s, ", ");
+
+ if (*value == '"') {
+ value++;
+ value[strlen(value) - 1] = '\0';
+ } else if (*value == '\0') {
+ break;
+ }
+
+ if (!strcmp(name, "username")) {
+ ah->user = value;
+ } else if (!strcmp(name, "cnonce")) {
+ ah->cnonce = value;
+ } else if (!strcmp(name, "response")) {
+ ah->response = value;
+ } else if (!strcmp(name, "uri")) {
+ ah->uri = value;
+ } else if (!strcmp(name, "qop")) {
+ ah->qop = value;
+ } else if (!strcmp(name, "nc")) {
+ ah->nc = value;
+ } else if (!strcmp(name, "nonce")) {
+ ah->nonce = value;
+ }
+ }
+
+ /* CGI needs it as REMOTE_USER */
+ if (ah->user != NULL)
+ conn->request_info.remote_user = mg_strdup(ah->user);
+
+ return (TRUE);
+}
+
+/*
+ * Authorize against the opened passwords file. Return 1 if authorized.
+ */
+static bool_t
+authorize(struct mg_connection *conn, FILE *fp)
+{
+ struct ah ah;
+ char line[256], f_user[256], domain[256], ha1[256],
+ buf[MAX_REQUEST_SIZE];
+
+ if (!parse_auth_header(conn, buf, sizeof(buf), &ah))
+ return (FALSE);
+
+ /* Loop over passwords file */
+ while (fgets(line, sizeof(line), fp) != NULL) {
+
+ if (sscanf(line, "%[^:]:%[^:]:%s", f_user, domain, ha1) != 3)
+ continue;
+
+ if (!strcmp(ah.user, f_user) &&
+ !strcmp(domain, conn->ctx->options[OPT_AUTH_DOMAIN]))
+ return (check_password(
+ conn->request_info.request_method, ha1,
+ ah.uri, ah.nonce, ah.nc, ah.cnonce,
+ ah.qop, ah.response));
+ }
+
+ return (FALSE);
+}
+
+/*
+ * Return TRUE if request is authorised, FALSE otherwise.
+ */
+static bool_t
+check_authorization(struct mg_connection *conn, const char *path)
+{
+ FILE *fp;
+ size_t len, n;
+ char protected_path[FILENAME_MAX];
+ const char *p, *s;
+ const struct callback *cb;
+ bool_t authorized;
+
+ fp = NULL;
+ authorized = TRUE;
+
+ mg_lock(conn->ctx);
+ s = conn->ctx->options[OPT_PROTECT];
+ FOR_EACH_WORD_IN_LIST(s, len) {
+
+ p = (const char *) memchr(s, '=', len);
+ if (p == NULL || p >= s + len || p == s)
+ continue;
+
+ if (!memcmp(conn->request_info.uri, s, p - s)) {
+
+ n = (size_t) (s + len - p);
+ if (n > sizeof(protected_path) - 1)
+ n = sizeof(protected_path) - 1;
+
+ mg_strlcpy(protected_path, p + 1, n);
+
+ if ((fp = fopen(protected_path, "r")) == NULL)
+ cry("check_auth: cannot open %s: %s",
+ protected_path, strerror(errno));
+ break;
+ }
+ }
+ mg_unlock(conn->ctx);
+
+ if (fp == NULL)
+ fp = open_auth_file(conn->ctx, path);
+
+ if (fp != NULL) {
+ authorized = authorize(conn, fp);
+ (void) fclose(fp);
+ }
+
+ if ((cb = find_callback(conn->ctx, TRUE,
+ conn->request_info.uri, -1)) != NULL) {
+ struct ah ah;
+ char buf[MAX_REQUEST_SIZE];
+ void *user_data = cb->user_data;
+
+ authorized = FALSE;
+ if (parse_auth_header(conn, buf, sizeof(buf), &ah)) {
+ cb->func(conn, &conn->request_info, &user_data);
+ authorized = (bool_t) (long) user_data;
+ }
+ }
+
+ return (authorized);
+}
+
+static void
+send_authorization_request(struct mg_connection *conn)
+{
+ (void) mg_printf(conn,
+ "HTTP/1.1 401 Unauthorized\r\n"
+ "WWW-Authenticate: Digest qop=\"auth\", "
+ "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
+ conn->ctx->options[OPT_AUTH_DOMAIN], (unsigned long) time(NULL));
+}
+
+static bool_t
+is_authorized_for_put(struct mg_connection *conn)
+{
+ FILE *fp;
+ int ret = FALSE;
+
+ if ((fp = fopen(conn->ctx->options[OPT_AUTH_PUT], "r")) != NULL) {
+ set_close_on_exec(fileno(fp));
+ ret = authorize(conn, fp);
+ (void) fclose(fp);
+ }
+
+ return (ret);
+}
+#endif /* NO_AUTH */
+
+static bool_t
+does_client_want_keep_alive(const struct mg_connection *conn)
+{
+ const char *value = mg_get_header(conn, "Connection");
+
+ /* HTTP/1.1 assumes keep-alive, if Connection header is not set */
+ return ((value == NULL && conn->request_info.http_version_major == 1 &&
+ conn->request_info.http_version_minor == 1) || (value != NULL &&
+ !mg_strcasecmp(value, "keep-alive")));
+}
+
+struct de {
+ struct mg_connection *conn;
+ char *file_name;
+ struct stat st;
+};
+
+static void
+print_dir_entry(struct de *de)
+{
+ char size[64], mod[64];
+
+ if (S_ISDIR(de->st.st_mode)) {
+ (void) mg_snprintf(size, sizeof(size), "%s", "<DIR>");
+ } else {
+ if (de->st.st_size < 1024)
+ (void) mg_snprintf(size, sizeof(size),
+ "%lu", (unsigned long) de->st.st_size);
+ else if (de->st.st_size < 1024 * 1024)
+ (void) mg_snprintf(size, sizeof(size),
+ "%.1fk", (double) de->st.st_size / 1024);
+ else if (de->st.st_size < 1024 * 1024 * 1024)
+ (void) mg_snprintf(size, sizeof(size),
+ "%.1fM", (double) de->st.st_size / 1048576);
+ else
+ (void) mg_snprintf(size, sizeof(size),
+ "%.1fG", (double) de->st.st_size / 1073741824);
+ }
+ (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
+ localtime(&de->st.st_mtime));
+ de->conn->num_bytes_sent += mg_printf(de->conn,
+ "<tr><td><a href=\"%s%s\">%s%s</a></td>"
+ "<td> %s</td><td> %s</td></tr>\n",
+ de->conn->request_info.uri, de->file_name, de->file_name,
+ S_ISDIR(de->st.st_mode) ? "/" : "", mod, size);
+}
+
+static int
+compare_dir_entries(const void *p1, const void *p2)
+{
+ const struct de *a = (struct de *) p1, *b = (struct de *) p2;
+ const char *q = a->conn->request_info.query_string;
+ int cmp_result = 0;
+
+ if (*q == 'n') {
+ cmp_result = strcmp(a->file_name, b->file_name);
+ } else if (*q == 's') {
+ cmp_result = a->st.st_size == b->st.st_size ? 0 :
+ a->st.st_size > b->st.st_size ? 1 : -1;
+ } else if (*q == 'd') {
+ cmp_result = a->st.st_mtime == b->st.st_mtime ? 0 :
+ a->st.st_mtime > b->st.st_mtime ? 1 : -1;
+ }
+
+ return (q[1] == 'd' ? -cmp_result : cmp_result);
+}
+
+static void
+send_directory(struct mg_connection *conn, const char *dir)
+{
+ struct dirent *dp;
+ DIR *dirp;
+ struct de *entries = NULL;
+ char path[FILENAME_MAX], sort_direction;
+ int i, num_entries = 0, arr_size = 128;
+
+ if ((dirp = opendir(dir)) == NULL) {
+ send_error(conn, 500, "Cannot open directory",
+ "Error: opendir(%s): %s", path, strerror(ERRNO));
+ return;
+ }
+
+ (void) mg_printf(conn, "%s",
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n\r\n");
+
+ sort_direction = conn->request_info.query_string != NULL &&
+ conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
+
+ while ((dp = readdir(dirp)) != NULL) {
+
+ /* Do not show current dir and passwords file */
+ if (!strcmp(dp->d_name, ".") ||
+ !strcmp(dp->d_name, "..") ||
+ !strcmp(dp->d_name, PASSWORDS_FILE_NAME))
+ continue;
+
+ if (entries == NULL || num_entries >= arr_size) {
+ arr_size *= 2;
+ entries = (struct de *) realloc(entries,
+ arr_size * sizeof(entries[0]));
+ }
+
+ if (entries == NULL) {
+ send_error(conn, 500, "Cannot open directory",
+ "%s", "Error: cannot allocate memory");
+ return;
+ }
+
+ (void) mg_snprintf(path, sizeof(path), "%s%c%s",
+ dir, DIRSEP, dp->d_name);
+
+ (void) stat(path, &entries[num_entries].st);
+ entries[num_entries].conn = conn;
+ entries[num_entries].file_name = mg_strdup(dp->d_name);
+ num_entries++;
+ }
+ (void) closedir(dirp);
+
+ if (conn->request_info.query_string != NULL)
+ qsort(entries, num_entries,
+ sizeof(entries[0]), compare_dir_entries);
+
+ conn->num_bytes_sent += mg_printf(conn,
+ "<html><head><title>Index of %s</title>"
+ "<style>th {text-align: left;}</style></head>"
+ "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
+ "<tr><th><a href=\"?n%c\">Name</a></th>"
+ "<th><a href=\"?d%c\">Modified</a></th>"
+ "<th><a href=\"?s%c\">Size</a></th></tr>"
+ "<tr><td colspan=\"3\"><hr></td></tr>",
+ conn->request_info.uri, conn->request_info.uri,
+ sort_direction, sort_direction, sort_direction);
+
+ /* Print first entry - link to a parent directory */
+ conn->num_bytes_sent += mg_printf(conn,
+ "<tr><td><a href=\"%s%s\">%s</a></td>"
+ "<td> %s</td><td> %s</td></tr>\n",
+ conn->request_info.uri, "..", "Parent directory", "-", "-");
+
+ for (i = 0; i < num_entries; i++) {
+ print_dir_entry(&entries[i]);
+ free(entries[i].file_name);
+ }
+ free(entries);
+
+ conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
+ conn->request_info.status_code = 200;
+}
+
+/*
+ * Send len bytes from the opened file to the client.
+ */
+static void
+send_opened_file_stream(struct mg_connection *conn, int fd, uint64_t len)
+{
+ char buf[BUFSIZ];
+ int n;
+
+ while (len > 0) {
+ n = sizeof(buf);
+ if ((uint64_t) n > len)
+ n = (int) len;
+ if ((n = read(fd, buf, n)) <= 0)
+ break;
+ conn->num_bytes_sent += mg_write(conn, buf, n);
+ len -= n;
+ }
+}
+
+static void
+send_file(struct mg_connection *conn, const char *path, struct stat *stp)
+{
+ char date[64], lm[64], etag[64], range[64];
+ const char *fmt = "%a, %d %b %Y %H:%M:%S GMT", *msg = "OK";
+ const char *mime_type, *s;
+ time_t curtime = time(NULL);
+ unsigned long long cl, r1, r2;
+ int fd, n;
+
+ mime_type = get_mime_type(path);
+ cl = stp->st_size;
+ conn->request_info.status_code = 200;
+ range[0] = '\0';
+
+ if ((fd = mg_open(path, O_RDONLY | O_BINARY, 0644)) == -1) {
+ send_error(conn, 500, http_500_error,
+ "fopen(%s): %s", path, strerror(ERRNO));
+ return;
+ }
+ set_close_on_exec(fd);
+
+ /* If Range: header specified, act accordingly */
+ s = mg_get_header(conn, "Range");
+ r1 = r2 = 0;
+ if (s != NULL && (n = sscanf(s,"bytes=%llu-%llu", &r1, &r2)) > 0) {
+ conn->request_info.status_code = 206;
+ (void) lseek(fd, (long) r1, SEEK_SET);
+ cl = n == 2 ? r2 - r1 + 1: cl - r1;
+ (void) mg_snprintf(range, sizeof(range),
+ "Content-Range: bytes %llu-%llu/%llu\r\n",
+ r1, r1 + cl - 1, cl);
+ msg = "Partial Content";
+ }
+
+ /* Prepare Etag, Date, Last-Modified headers */
+ (void) strftime(date, sizeof(date), fmt, localtime(&curtime));
+ (void) strftime(lm, sizeof(lm), fmt, localtime(&stp->st_mtime));
+ (void) mg_snprintf(etag, sizeof(etag), "%lx.%lx",
+ (unsigned long) stp->st_mtime, (unsigned long) stp->st_size);
+
+ /* Since we send Content-Length, we can keep the connection alive */
+ conn->keep_alive = does_client_want_keep_alive(conn);
+
+ (void) mg_printf(conn,
+ "HTTP/1.1 %d %s\r\n"
+ "Date: %s\r\n"
+ "Last-Modified: %s\r\n"
+ "Etag: \"%s\"\r\n"
+ "Content-Type: %s\r\n"
+ "Content-Length: %llu\r\n"
+ "Connection: %s\r\n"
+ "Accept-Ranges: bytes\r\n"
+ "%s\r\n",
+ conn->request_info.status_code, msg, date, lm, etag, mime_type, cl,
+ conn->keep_alive ? "keep-alive" : "close", range);
+
+ if (strcmp(conn->request_info.request_method, "HEAD") != 0)
+ send_opened_file_stream(conn, fd, cl);
+ (void) close(fd);
+}
+
+static void
+parse_http_headers(char **buf, struct mg_request_info *ri)
+{
+ int i;
+
+ for (i = 0; i < MAX_HTTP_HEADERS; i++) {
+ ri->http_headers[i].name = skip(buf, ": ");
+ ri->http_headers[i].value = skip(buf, "\r\n");
+ if (ri->http_headers[i].name[0] == '\0')
+ break;
+ ri->num_headers = i + 1;
+ }
+}
+
+static bool_t
+is_known_http_method(const char *method)
+{
+ return (!strcmp(method, "GET") ||
+ !strcmp(method, "POST") ||
+ !strcmp(method, "HEAD") ||
+ !strcmp(method, "PUT") ||
+ !strcmp(method, "DELETE"));
+}
+
+static bool_t
+parse_http_request(char *buf, struct mg_request_info *ri, const struct usa *usa)
+{
+ char *http_version;
+ int n, success_code = FALSE;
+
+ ri->request_method = skip(&buf, " ");
+ ri->uri = skip(&buf, " ");
+ http_version = skip(&buf, "\r\n");
+
+ if (is_known_http_method(ri->request_method) &&
+ ri->uri[0] == '/' &&
+ sscanf(http_version, "HTTP/%d.%d%n",
+ &ri->http_version_major, &ri->http_version_minor, &n) == 2 &&
+ http_version[n] == '\0') {
+ parse_http_headers(&buf, ri);
+ ri->remote_port = ntohs(usa->u.sin.sin_port);
+ (void) memcpy(&ri->remote_ip, &usa->u.sin.sin_addr.s_addr, 4);
+ ri->remote_ip = ntohl(ri->remote_ip);
+ success_code = TRUE;
+ }
+
+ return (success_code);
+}
+
+static int
+read_request(int fd, SOCKET sock, SSL *ssl, char *buf, int bufsiz, int *nread)
+{
+ int n, request_len;
+
+ request_len = 0;
+ while (*nread < bufsiz && request_len == 0) {
+ n = pull(fd, sock, ssl, buf + *nread, bufsiz - *nread);
+ if (n <= 0) {
+ break;
+ } else {
+ *nread += n;
+ request_len = get_request_len(buf, (size_t) *nread);
+ }
+ }
+
+ return (request_len);
+}
+
+/*
+ * For given directory path, substitute it to valid index file.
+ * Return 0 if index file has been found, -1 if not found
+ */
+static bool_t
+send_index_file(struct mg_connection *conn,
+ char *buf, size_t buf_len, struct stat *stp)
+{
+ const char *s;
+ size_t len, n;
+
+ n = strlen(buf);
+ buf[n] = DIRSEP;
+
+ mg_lock(conn->ctx);
+ s = conn->ctx->options[OPT_INDEX_FILES];
+ FOR_EACH_WORD_IN_LIST(s, len) {
+ if (len > buf_len - n - 1)
+ continue;
+ (void) mg_strlcpy(buf + n + 1, s, len + 1);
+ if (stat(buf, stp) == 0) {
+ send_file(conn, buf, stp);
+ mg_unlock(conn->ctx);
+ return (TRUE);
+ }
+ }
+ mg_unlock(conn->ctx);
+
+ buf[n] = '\0';
+
+ return (FALSE);
+}
+
+static void
+mg_bind(struct mg_context *ctx, const char *uri_regex, int status_code,
+ mg_callback_t func, bool_t is_auth, void *user_data)
+{
+ struct callback *cb;
+
+ if (ctx->num_callbacks >= (int) ARRAY_SIZE(ctx->callbacks) - 1) {
+ cry("Too many callbacks! Increase MAX_CALLBACKS.");
+ } else {
+ cb = &ctx->callbacks[ctx->num_callbacks];
+ cb->uri_regex = uri_regex ? mg_strdup(uri_regex) : NULL;
+ cb->func = func;
+ cb->is_auth = is_auth;
+ cb->status_code = status_code;
+ cb->user_data = user_data;
+ ctx->num_callbacks++;
+ }
+}
+
+void
+mg_bind_to_uri(struct mg_context *ctx, const char *uri_regex,
+ mg_callback_t func, void *user_data)
+{
+ assert(func != NULL);
+ assert(uri_regex != NULL);
+ mg_bind(ctx, uri_regex, -1, func, FALSE, user_data);
+}
+
+void
+mg_bind_to_error_code(struct mg_context *ctx, int error_code,
+ mg_callback_t func, void *user_data)
+{
+ assert(error_code >= 0 && error_code < 1000);
+ assert(func != NULL);
+ mg_bind(ctx, NULL, error_code, func, FALSE, user_data);
+}
+
+void
+mg_protect_uri(struct mg_context *ctx, const char *uri_regex,
+ mg_callback_t func, void *user_data)
+{
+ assert(func != NULL);
+ assert(uri_regex != NULL);
+ mg_bind(ctx, uri_regex, -1, func, TRUE, user_data);
+}
+
+static int
+not_modified(const struct mg_connection *conn, const struct stat *stp)
+{
+ const char *ims = mg_get_header(conn, "If-Modified-Since");
+ return (ims != NULL && stp->st_mtime < date_to_epoch(ims));
+}
+
+static bool_t
+append_chunk(struct mg_request_info *ri, int fd, const char *buf, int len)
+{
+ bool_t ret_code = TRUE;
+
+ if (fd == -1) {
+ /* TODO: check for NULL here */
+ ri->post_data = (char *) realloc(ri->post_data,
+ ri->post_data_len + len);
+ (void) memcpy(ri->post_data + ri->post_data_len, buf, len);
+ ri->post_data_len += len;
+ } else if (push(fd, INVALID_SOCKET,
+ NULL, buf, (uint64_t) len) != (uint64_t) len) {
+ ret_code = FALSE;
+ }
+
+ return (ret_code);
+}
+
+static bool_t
+handle_request_body(struct mg_connection *conn, int fd)
+{
+ struct mg_request_info *ri = &conn->request_info;
+ const char *expect, *tmp;
+ uint64_t content_len;
+ char buf[BUFSIZ];
+ int to_read, nread, already_read;
+ bool_t success_code = FALSE;
+
+ content_len = get_content_length(conn);
+ expect = mg_get_header(conn, "Expect");
+
+ if (content_len == UNKNOWN_CONTENT_LENGTH) {
+ send_error(conn, 411, "Length Required", "");
+ } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
+ send_error(conn, 417, "Expectation Failed", "");
+ } else {
+ if (expect != NULL)
+ (void) mg_printf(conn, "HTTP/1.1 100 Continue\r\n\r\n");
+
+ already_read = ri->post_data_len;
+ assert(already_read >= 0);
+
+ if (content_len <= (uint64_t) already_read) {
+ ri->post_data_len = (int) content_len;
+ /*
+ * If fd == -1, this is embedded mode, and we do not
+ * have to do anything: POST data is already there,
+ * no need to allocate a buffer and copy it in.
+ * If fd != -1, we need to write the data.
+ */
+ success_code = (fd == -1) || (push(fd, INVALID_SOCKET,
+ NULL, ri->post_data, content_len) == content_len) ?
+ TRUE : FALSE;
+ } else {
+
+ if (fd == -1) {
+ conn->free_post_data = TRUE;
+ tmp = ri->post_data;
+ /* +1 in case if already_read == 0 */
+ ri->post_data = (char*)malloc(already_read + 1);
+ (void) memcpy(ri->post_data, tmp, already_read);
+ } else {
+ (void) push(fd, INVALID_SOCKET, NULL,
+ ri->post_data, (uint64_t) already_read);
+ }
+
+ content_len -= already_read;
+
+ while (content_len > 0) {
+ to_read = sizeof(buf);
+ if ((uint64_t) to_read > content_len)
+ to_read = (int) content_len;
+ nread = pull(-1, conn->sock,
+ conn->ssl, buf, to_read);
+ if (nread <= 0)
+ break;
+ if (!append_chunk(ri, fd, buf, nread))
+ break;
+ content_len -= nread;
+ }
+ success_code = content_len == 0 ? TRUE : FALSE;
+ }
+
+ /* Each error code path in this function must send an error */
+ if (success_code != TRUE)
+ send_error(conn, 577, http_500_error,
+ "%s", "Error handling body data");
+ }
+
+ return (success_code);
+}
+
+#if !defined(NO_CGI)
+struct cgi_env_block {
+ char buf[CGI_ENVIRONMENT_SIZE]; /* Environment buffer */
+ int len; /* Space taken */
+ char *vars[MAX_CGI_ENVIR_VARS]; /* char **envp */
+ int nvars; /* Number of variables */
+};
+
+static char *
+addenv(struct cgi_env_block *block, const char *fmt, ...)
+{
+ int n, space;
+ char *added;
+ va_list ap;
+
+ space = sizeof(block->buf) - block->len - 2;
+ assert(space >= 0);
+ added = block->buf + block->len;
+
+ va_start(ap, fmt);
+ n = mg_vsnprintf(added, (size_t) space, fmt, ap);
+ va_end(ap);
+
+ if (n > 0 && n < space &&
+ block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
+ block->vars[block->nvars++] = block->buf + block->len;
+ block->len += n + 1; /* Include \0 terminator */
+ }
+
+ return (added);
+}
+
+static void
+prepare_cgi_environment(struct mg_connection *conn, const char *prog,
+ struct cgi_env_block *blk)
+{
+ const char *s, *script_filename, *root;
+ char *p;
+ int i;
+
+ blk->len = blk->nvars = 0;
+
+ /* SCRIPT_FILENAME */
+ script_filename = prog;
+ if ((s = strrchr(prog, '/')) != NULL)
+ script_filename = s + 1;
+
+ mg_lock(conn->ctx);
+ root = conn->ctx->options[OPT_ROOT];
+ addenv(blk, "SERVER_NAME=%s", conn->ctx->options[OPT_AUTH_DOMAIN]);
+ mg_unlock(conn->ctx);
+
+ /* Prepare the environment block */
+ addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
+ addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
+ addenv(blk, "%s", "REDIRECT_STATUS=200"); /* PHP */
+ addenv(blk, "SERVER_PORT=%d", ntohs(conn->lsa.u.sin.sin_port));
+ addenv(blk, "SERVER_ROOT=%s", root);
+ addenv(blk, "DOCUMENT_ROOT=%s", root);
+ addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
+ addenv(blk, "REMOTE_ADDR=%s", inet_ntoa(conn->rsa.u.sin.sin_addr));
+ addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
+ addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
+ addenv(blk, "SCRIPT_NAME=%s", prog + strlen(root));
+ addenv(blk, "SCRIPT_FILENAME=%s", script_filename); /* PHP */
+ addenv(blk, "PATH_TRANSLATED=%s", prog);
+
+ if ((s = mg_get_header(conn, "Content-Type")) != NULL)
+ addenv(blk, "CONTENT_TYPE=%s", s);
+
+ if (conn->request_info.query_string != NULL)
+ addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
+
+ if ((s = mg_get_header(conn, "Content-Length")) != NULL)
+ addenv(blk, "CONTENT_LENGTH=%s", s);
+
+ if ((s = getenv("PATH")) != NULL)
+ addenv(blk, "PATH=%s", s);
+
+#if defined(_WIN32)
+ if ((s = getenv("COMSPEC")) != NULL)
+ addenv(blk, "COMSPEC=%s", s);
+ if ((s = getenv("SYSTEMROOT")) != NULL)
+ addenv(blk, "SYSTEMROOT=%s", s);
+#else
+ if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
+ addenv(blk, "LD_LIBRARY_PATH=%s", s);
+#endif /* _WIN32 */
+
+ if ((s = getenv("PERLLIB")) != NULL)
+ addenv(blk, "PERLLIB=%s", s);
+
+ if (conn->request_info.remote_user != NULL) {
+ addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user);
+ addenv(blk, "%s", "AUTH_TYPE=Digest");
+ }
+
+ /* Add all headers as HTTP_* variables */
+ for (i = 0; i < conn->request_info.num_headers; i++) {
+ p = addenv(blk, "HTTP_%s=%s",
+ conn->request_info.http_headers[i].name,
+ conn->request_info.http_headers[i].value);
+
+ /* Convert variable name into uppercase, and change - to _ */
+ for (; *p != '=' && *p != '\0'; p++) {
+ if (*p == '-')
+ *p = '_';
+ *p = toupper(* (unsigned char *) p) & 0xff;
+ }
+ }
+
+ blk->vars[blk->nvars++] = NULL;
+ blk->buf[blk->len++] = '\0';
+
+ assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
+ assert(blk->len > 0);
+ assert(blk->len < (int) sizeof(blk->buf));
+}
+
+static void
+send_cgi(struct mg_connection *conn, const char *prog)
+{
+ int headers_len, data_len, i, n;
+ const char *status;
+ char buf[MAX_REQUEST_SIZE], *pbuf;
+ struct mg_request_info ri;
+ struct cgi_env_block blk;
+ char dir[FILENAME_MAX], *p;
+ int fd_stdin[2], fd_stdout[2];
+
+ prepare_cgi_environment(conn, prog, &blk);
+
+ /* CGI must be executed in its own directory */
+ (void) mg_snprintf(dir, sizeof(dir), "%s", prog);
+ if ((p = strrchr(dir, DIRSEP)) != NULL)
+ *p++ = '\0';
+
+ fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
+ if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
+ send_error(conn, 500, http_500_error,
+ "Cannot create CGI pipe: %s", strerror(ERRNO));
+ goto done;
+ }
+
+ if (!spawn_process(conn, p, blk.buf, blk.vars,
+ fd_stdin[0], fd_stdout[1], dir)) {
+ goto done;
+ }
+
+ /*
+ * spawn_process() must close those!
+ * If we don't mark them as closed, close() attempt before
+ * return from this function throws an exception on Windows.
+ * Windows does not like when closed descriptor is closed again.
+ */
+ fd_stdin[0] = fd_stdout[1] = -1;
+
+ /* Send POST data to the CGI process if needed */
+ if (!strcmp(conn->request_info.request_method, "POST") &&
+ !handle_request_body(conn, fd_stdin[1])) {
+ goto done;
+ }
+
+ /*
+ * Now read CGI reply into a buffer. We need to set correct
+ * status code, thus we need to see all HTTP headers first.
+ * Do not send anything back to client, until we buffer in all
+ * HTTP headers.
+ */
+ data_len = 0;
+ headers_len = read_request(fd_stdout[0], INVALID_SOCKET, NULL,
+ buf, sizeof(buf), &data_len);
+ if (headers_len <= 0) {
+ send_error(conn, 500, http_500_error,
+ "CGI program sent malformed HTTP headers: [%.*s]",
+ data_len, buf);
+ goto done;
+ }
+ pbuf = buf;
+ buf[headers_len - 1] = '\0';
+ parse_http_headers(&pbuf, &ri);
+
+ /* Make up and send the status line */
+ status = get_header(&ri, "Status");
+ conn->request_info.status_code = status == NULL ? 200 : atoi(status);
+ (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n",
+ conn->request_info.status_code);
+
+ /* Send headers */
+ for (i = 0; i < ri.num_headers; i++)
+ (void) mg_printf(conn, "%s: %s\r\n",
+ ri.http_headers[i].name,
+ ri.http_headers[i].value);
+ (void) mg_write(conn, "\r\n", 2);
+
+ /* Send headers, and the rest of the data */
+ conn->num_bytes_sent += mg_write(conn,
+ buf + headers_len, data_len - headers_len);
+ while ((n = pull(fd_stdout[0],
+ INVALID_SOCKET, NULL, buf, sizeof(buf))) > 0)
+ conn->num_bytes_sent += mg_write(conn, buf, n);
+
+done:
+ if (fd_stdin[0] != -1) (void) close(fd_stdin[0]);
+ if (fd_stdin[1] != -1) (void) close(fd_stdin[1]);
+ if (fd_stdout[0] != -1) (void) close(fd_stdout[0]);
+ if (fd_stdout[1] != -1) (void) close(fd_stdout[1]);
+}
+#endif /* !NO_CGI */
+
+#if !defined(NO_AUTH)
+/*
+ * For a given PUT path, create all intermediate subdirectories
+ * for given path. Return 0 if the path itself is a directory,
+ * or -1 on error, 1 if OK.
+ */
+static int
+put_dir(const char *path)
+{
+ char buf[FILENAME_MAX];
+ const char *s, *p;
+ struct stat st;
+ size_t len;
+
+ for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
+ len = p - path;
+ assert(len < sizeof(buf));
+ (void) memcpy(buf, path, len);
+ buf[len] = '\0';
+
+ /* Try to create intermediate directory */
+ if (mg_stat(buf, &st) == -1 && mg_mkdir(buf, 0755) != 0)
+ return (-1);
+
+ /* Is path itself a directory ? */
+ if (p[1] == '\0')
+ return (0);
+ }
+
+ return (1);
+}
+
+static void
+put_file(struct mg_connection *conn, const char *path)
+{
+ struct stat st;
+ int rc, fd;
+
+ conn->request_info.status_code = mg_stat(path, &st) == 0 ? 200 : 201;
+
+ if (mg_get_header(conn, "Range")) {
+ send_error(conn, 501, "Not Implemented",
+ "%s", "Range support for PUT requests is not implemented");
+ } else if ((rc = put_dir(path)) == 0) {
+ send_error(conn, 200, "OK", "");
+ } else if (rc == -1) {
+ send_error(conn, 500, http_500_error,
+ "put_dir(%s): %s", path, strerror(ERRNO));
+ } else if ((fd = mg_open(path,
+ O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0644)) == -1) {
+ send_error(conn, 500, http_500_error,
+ "open(%s): %s", path, strerror(ERRNO));
+ } else {
+ set_close_on_exec(fd);
+ if (handle_request_body(conn, fd))
+ send_error(conn, conn->request_info.status_code,
+ "OK", "");
+ (void) close(fd);
+ }
+}
+#endif /* NO_AUTH */
+
+#if !defined(NO_SSI)
+static void
+do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag)
+{
+ char file_name[BUFSIZ], path[FILENAME_MAX], *p;
+ FILE *fp;
+
+ /*
+ * sscanf() is safe here, since send_ssi_file() also uses buffer
+ * of size BUFSIZ to get the tag. So strlen(tag) is always < BUFSIZ.
+ */
+ if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
+ /* File name is relative to the webserver root */
+ mg_lock(conn->ctx);
+ (void) mg_snprintf(path, sizeof(path), "%s%c%s",
+ conn->ctx->options[OPT_ROOT], DIRSEP, file_name);
+ mg_unlock(conn->ctx);
+ } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1) {
+ /*
+ * File name is relative to the webserver working directory
+ * or it is absolute system path
+ */
+ (void) mg_snprintf(path, sizeof(path), "%s", file_name);
+ } else if (sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
+ /* File name is relative to the currect document */
+ (void) mg_snprintf(path, sizeof(path), "%s", ssi);
+ if ((p = strrchr(path, DIRSEP)) != NULL)
+ p[1] = '\0';
+ (void) mg_snprintf(path + strlen(path),
+ sizeof(path) - strlen(path), "%s", file_name);
+ } else {
+ cry("Bad SSI #include: [%s]", tag);
+ return;
+ }
+
+ if ((fp = fopen(path, "rb")) == NULL) {
+ cry("Cannot open SSI #include: [%s]: fopen(%s): %s",
+ tag, path, strerror(ERRNO));
+ } else {
+ set_close_on_exec(fileno(fp));
+ send_opened_file_stream(conn, fileno(fp), ~0ULL);
+ (void) fclose(fp);
+ }
+}
+
+static void
+do_ssi_exec(struct mg_connection *conn, char *tag)
+{
+ char cmd[BUFSIZ];
+ FILE *fp;
+
+ if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
+ cry("Bad SSI #exec: [%s]", tag);
+ } else if ((fp = popen(cmd, "r")) == NULL) {
+ cry("Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
+ } else {
+ send_opened_file_stream(conn, fileno(fp), ~0ULL);
+ (void) pclose(fp);
+ }
+}
+
+static void
+send_ssi_file(struct mg_connection *conn, const char *path, FILE *fp)
+{
+ char buf[BUFSIZ];
+ int ch, len, in_ssi_tag;
+
+ in_ssi_tag = FALSE;
+ len = 0;
+
+ while ((ch = fgetc(fp)) != EOF) {
+ if (in_ssi_tag && ch == '>') {
+ in_ssi_tag = FALSE;
+ buf[len++] = ch & 0xff;
+ buf[len] = '\0';
+ assert(len <= (int) sizeof(buf));
+ if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
+ /* Not an SSI tag, pass it */
+ (void) mg_write(conn, buf, len);
+ } else {
+ if (!memcmp(buf + 5, "include", 7)) {
+ do_ssi_include(conn, path, buf + 12);
+ } else if (!memcmp(buf + 5, "exec", 4)) {
+ do_ssi_exec(conn, buf + 9);
+ } else {
+ cry("%s: unknown SSI command: \"%s\"",
+ path, buf);
+ }
+ }
+ len = 0;
+ } else if (in_ssi_tag) {
+ if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
+ /* Not an SSI tag */
+ in_ssi_tag = FALSE;
+ } else if (len == (int) sizeof(buf) - 2) {
+ cry("%s: SSI tag is too large", path);
+ len = 0;
+ }
+ buf[len++] = ch & 0xff;
+ } else if (ch == '<') {
+ in_ssi_tag = TRUE;
+ if (len > 0)
+ (void) mg_write(conn, buf, len);
+ len = 0;
+ buf[len++] = ch & 0xff;
+ } else {
+ buf[len++] = ch & 0xff;
+ if (len == (int) sizeof(buf)) {
+ (void) mg_write(conn, buf, len);
+ len = 0;
+ }
+ }
+ }
+
+ /* Send the rest of buffered data */
+ if (len > 0)
+ (void) mg_write(conn, buf, len);
+
+}
+
+static void
+send_ssi(struct mg_connection *conn, const char *path)
+{
+ FILE *fp;
+
+ if ((fp = fopen(path, "rb")) == NULL) {
+ send_error(conn, 500, http_500_error,
+ "fopen(%s): %s", path, strerror(ERRNO));
+ } else {
+ set_close_on_exec(fileno(fp));
+ (void) mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\nConnection: close\r\n\r\n");
+ send_ssi_file(conn, path, fp);
+ (void) fclose(fp);
+ }
+}
+#endif /* !NO_SSI */
+
+static void
+analyze_request(struct mg_connection *conn)
+{
+ struct mg_request_info *ri = &conn->request_info;
+ char path[FILENAME_MAX], *uri = ri->uri;
+ struct stat st;
+ const struct callback *cb;
+
+ if ((conn->request_info.query_string = strchr(uri, '?')) != NULL)
+ * conn->request_info.query_string++ = '\0';
+
+ (void) url_decode(uri, (int) strlen(uri), uri, strlen(uri) + 1, FALSE);
+ remove_double_dots(uri);
+ make_path(conn->ctx, uri, path, sizeof(path));
+
+#if !defined(NO_AUTH)
+ if (!check_authorization(conn, path)) {
+ send_authorization_request(conn);
+ } else
+#endif /* !NO_AUTH */
+ if ((cb = find_callback(conn->ctx, FALSE, uri, -1)) != NULL) {
+ if (strcmp(ri->request_method, "POST") ||
+ (!strcmp(ri->request_method, "POST") &&
+ handle_request_body(conn, -1)))
+ cb->func(conn, &conn->request_info, cb->user_data);
+ } else
+#if !defined(NO_AUTH)
+ if (strstr(path, PASSWORDS_FILE_NAME)) {
+ /* Do not allow to view passwords files */
+ send_error(conn, 403, "Forbidden", "");
+ } else if ((!strcmp(ri->request_method, "PUT") ||
+ !strcmp(ri->request_method, "DELETE")) &&
+ (conn->ctx->options[OPT_AUTH_PUT] == NULL ||
+ !is_authorized_for_put(conn))) {
+ send_authorization_request(conn);
+ } else if (!strcmp(ri->request_method, "PUT")) {
+ put_file(conn, path);
+ } else if (!strcmp(ri->request_method, "DELETE")) {
+ if (mg_remove(path) == 0)
+ send_error(conn, 200, "OK", "");
+ else
+ send_error(conn, 500, http_500_error,
+ "remove(%s): %s", path, strerror(ERRNO));
+ } else
+#endif /* NO_AUTH */
+ if (mg_stat(path, &st) != 0) {
+ send_error(conn, 404, "Not Found", "%s", "");
+ } else if (S_ISDIR(st.st_mode) && uri[strlen(uri) - 1] != '/') {
+ (void) mg_printf(conn,
+ "HTTP/1.1 301 Moved Permanently\r\n"
+ "Location: %s/\r\n\r\n", uri);
+ } else if (S_ISDIR(st.st_mode)) {
+ if (send_index_file(conn, path, sizeof(path), &st)) {
+ /* do nothing */
+ } else if (is_true(conn->ctx->options[OPT_DIR_LIST])) {
+ send_directory(conn, path);
+ } else {
+ send_error(conn, 403, "Directory Listing Denied",
+ "Directory listing denied");
+ }
+#if !defined(NO_CGI)
+ } else if (match_extension(path,
+ conn->ctx->options[OPT_CGI_EXTENSIONS])) {
+ if (strcmp(ri->request_method, "POST") &&
+ strcmp(ri->request_method, "GET")) {
+ send_error(conn, 501, "Not Implemented",
+ "Method %s is not implemented", ri->request_method);
+ } else {
+ send_cgi(conn, path);
+ }
+#endif /* NO_CGI */
+#if !defined(NO_SSI)
+ } else if (match_extension(path,
+ conn->ctx->options[OPT_SSI_EXTENSIONS])) {
+ send_ssi(conn, path);
+#endif /* NO_SSI */
+ } else if (not_modified(conn, &st)) {
+ send_error(conn, 304, "Not Modified", "");
+ } else {
+ send_file(conn, path, &st);
+ }
+}
+
+static void
+close_all_listening_sockets(struct mg_context *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->num_listeners; i++)
+ (void) closesocket(ctx->listeners[i].sock);
+ ctx->num_listeners = 0;
+}
+
+static bool_t
+set_ports_option(struct mg_context *ctx, const char *p)
+{
+ SOCKET sock;
+ size_t len;
+ int is_ssl, port;
+
+ close_all_listening_sockets(ctx);
+
+ FOR_EACH_WORD_IN_LIST(p, len) {
+
+ is_ssl = p[len - 1] == 's' ? 1 : 0;
+ port = atoi(p);
+
+ if (ctx->num_listeners >=
+ (int) (ARRAY_SIZE(ctx->listeners) - 1)) {
+ cry("%s", "Too many listeninig sockets");
+ return (FALSE);
+ } else if ((sock = mg_open_listening_port(port)) == -1) {
+ cry("cannot open port %d", port);
+ return (FALSE);
+ } else if (is_ssl && ctx->ssl_ctx == NULL) {
+ (void) closesocket(sock);
+ cry("cannot add SSL socket, "
+ "please specify certificate file");
+ return (FALSE);
+ } else {
+ ctx->listeners[ctx->num_listeners].sock = sock;
+ ctx->listeners[ctx->num_listeners].is_ssl = is_ssl;
+ ctx->num_listeners++;
+ }
+ }
+
+ return (TRUE);
+}
+
+static void
+log_header(const struct mg_connection *conn, const char *header, FILE *fp)
+{
+ const char *header_value;
+
+ if ((header_value = mg_get_header(conn, header)) == NULL) {
+ (void) fprintf(fp, "%s", " -");
+ } else {
+ (void) fprintf(fp, " \"%s\"", header_value);
+ }
+}
+
+static void
+log_access(const struct mg_connection *conn)
+{
+ const struct mg_request_info *ri;
+ char date[64];
+
+ if (conn->ctx->access_log == NULL)
+ return;
+
+ (void) strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S",
+ localtime(&conn->birth_time));
+
+ ri = &conn->request_info;
+ (void) fprintf(conn->ctx->access_log,
+ "%s - %s [%s %+05d] \"%s %s HTTP/%d.%d\" %d %llu",
+ inet_ntoa(conn->rsa.u.sin.sin_addr),
+ ri->remote_user == NULL ? "-" : ri->remote_user,
+ date, tz_offset,
+ ri->request_method ? ri->request_method : "-",
+ ri->uri ? ri->uri : "-",
+ ri->http_version_major, ri->http_version_minor,
+ conn->request_info.status_code,
+ (unsigned long long) conn->num_bytes_sent);
+ log_header(conn, "Referer", conn->ctx->access_log);
+ log_header(conn, "User-Agent", conn->ctx->access_log);
+ (void) fputc('\n', conn->ctx->access_log);
+ (void) fflush(conn->ctx->access_log);
+}
+
+static bool_t
+isbyte(int n) {
+ return (n >= 0 && n <= 255);
+}
+
+static bool_t
+check_acl(struct mg_context *ctx, const struct usa *usa)
+{
+ int a, b, c, d, n, mask, allowed;
+ char flag, *s;
+ size_t len;
+ uint32_t acl_subnet, acl_mask, remote_ip;
+
+ (void) memcpy(&remote_ip, &usa->u.sin.sin_addr, sizeof(remote_ip));
+
+ mg_lock(ctx);
+ s = ctx->options[OPT_ACL];
+
+ /* Allow by default, if no ACL is set */
+ if (s == NULL) {
+ mg_unlock(ctx);
+ return (TRUE);
+ }
+
+ /* If any ACL is set, deny by default */
+ allowed = '-';
+ FOR_EACH_WORD_IN_LIST(s, len) {
+
+ mask = 32;
+
+ if (sscanf(s, "%c%d.%d.%d.%d%n",&flag,&a,&b,&c,&d,&n) != 5) {
+ cry("[%s]: subnet must be [+|-]x.x.x.x[/x]", s);
+ } else if (flag != '+' && flag != '-') {
+ cry("flag must be + or -: [%s]", s);
+ } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
+ cry("bad ip address: [%s]", s);
+ } else if (sscanf(s + n, "/%d", &mask) == 0) {
+ /* Do nothing, no mask specified */
+ } else if (mask < 0 || mask > 32) {
+ cry("bad subnet mask: %d [%s]", n, s);
+ }
+
+ acl_subnet = (a << 24) | (b << 16) | (c << 8) | d;
+ acl_mask = mask ? 0xffffffffU << (32 - mask) : 0;
+
+ if (acl_subnet == (ntohl(remote_ip) & acl_mask))
+ allowed = flag;
+ }
+ mg_unlock(ctx);
+
+ return (allowed == '+');
+}
+
+static void
+add_to_set(SOCKET fd, fd_set *set, int *max_fd)
+{
+ FD_SET(fd, set);
+ if (fd > (SOCKET) *max_fd)
+ *max_fd = (int) fd;
+}
+
+/*
+ * Deallocate mongoose context, free up the resources
+ */
+static void
+mg_fini(struct mg_context *ctx)
+{
+ int i;
+
+ close_all_listening_sockets(ctx);
+
+ for (i = 0; i < ctx->num_callbacks; i++)
+ if (ctx->callbacks[i].uri_regex != NULL)
+ free(ctx->callbacks[i].uri_regex);
+
+ for (i = 0; i < NUM_OPTIONS; i++)
+ if (ctx->options[i] != NULL)
+ free(ctx->options[i]);
+
+ if (ctx->access_log)
+ (void) fclose(ctx->access_log);
+ if (ctx->error_log)
+ (void) fclose(ctx->error_log);
+
+ /* TODO: free SSL context */
+ (void) pthread_mutex_destroy(&ctx->mutex);
+ destroy_socket_pool(&ctx->socket_pool);
+
+ free(ctx);
+}
+
+#if !defined(_WIN32)
+static bool_t
+set_uid_option(struct mg_context *ctx, const char *uid)
+{
+ struct passwd *pw;
+ int retval = FALSE;
+
+ ctx = NULL; /* Unused */
+
+ if ((pw = getpwnam(uid)) == NULL)
+ cry("%s: unknown user [%s]", __func__, uid);
+ else if (setgid(pw->pw_gid) == -1)
+ cry("%s: setgid(%s): %s", __func__, uid, strerror(errno));
+ else if (setuid(pw->pw_uid) == -1)
+ cry("%s: setuid(%s): %s", __func__, uid, strerror(errno));
+ else
+ retval = TRUE;
+
+ return (retval);
+}
+#endif /* !_WIN32 */
+
+#if !defined(NO_SSL)
+void
+mg_set_ssl_password_callback(struct mg_context *ctx, mg_spcb_t func)
+{
+ ctx->ssl_password_callback = func;
+}
+
+/*
+ * Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
+ */
+static bool_t
+set_ssl_option(struct mg_context *ctx, const char *pem)
+{
+ SSL_CTX *CTX;
+ void *lib;
+ union {void *p; void (*fp)(void);} u;
+ struct ssl_func *fp;
+ int retval = FALSE;
+
+ /* Load SSL library dynamically */
+ if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL) {
+ cry("set_ssl_option: cannot load %s", SSL_LIB);
+ return (FALSE);
+ }
+
+ for (fp = ssl_sw; fp->name != NULL; fp++) {
+#ifdef _WIN32
+ /* GetProcAddress() returns pointer to function */
+ u.fp = (void (*)(void)) dlsym(lib, fp->name);
+#else
+ /*
+ * dlsym() on UNIX returns void *.
+ * ISO C forbids casts of data pointers to function
+ * pointers. We need to use a union to make a cast.
+ */
+ u.p = dlsym(lib, fp->name);
+#endif /* _WIN32 */
+ if (u.fp == NULL) {
+ cry("set_ssl_option: cannot find %s", fp->name);
+ return (FALSE);
+ } else {
+ fp->ptr = u.fp;
+ }
+ }
+
+ /* Initialize SSL crap */
+ SSL_library_init();
+
+ if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
+ cry("SSL_CTX_new error");
+ else if (ctx->ssl_password_callback != NULL)
+ SSL_CTX_set_default_passwd_cb(CTX, ctx->ssl_password_callback);
+
+ if (CTX != NULL && SSL_CTX_use_certificate_file(
+ CTX, pem, SSL_FILETYPE_PEM) == 0)
+ cry("cannot open %s", pem);
+ else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(
+ CTX, pem, SSL_FILETYPE_PEM) == 0)
+ cry("cannot open %s", pem);
+ else
+ retval = TRUE;
+
+ ctx->ssl_ctx = CTX;
+
+ return (retval);
+}
+#endif /* !NO_SSL */
+
+static bool_t
+open_log_file(FILE **fpp, const char *path)
+{
+ bool_t retval = TRUE;
+
+ if (*fpp != NULL)
+ (void) fclose(*fpp);
+
+ if (path == NULL) {
+ *fpp = NULL;
+ } else if ((*fpp = fopen(path, "a")) == NULL) {
+ cry("cannot open log file %s: %s",
+ path, strerror(errno));
+ retval = FALSE;
+ } else {
+ set_close_on_exec(fileno(*fpp));
+ }
+
+ return (retval);
+}
+
+static bool_t
+set_alog_option(struct mg_context *ctx, const char *path)
+{
+ return (open_log_file(&ctx->access_log, path));
+}
+
+static bool_t
+set_elog_option(struct mg_context *ctx, const char *path)
+{
+ return (open_log_file(&ctx->error_log, path));
+}
+
+#if !defined(NO_AUTH)
+static bool_t
+set_gpass_option(struct mg_context *ctx, const char *path)
+{
+ ctx = NULL;
+ return (access(path, R_OK) == 0);
+}
+#endif /* !NO_AUTH */
+
+static void
+admin_page(struct mg_connection *conn, const struct mg_request_info *ri,
+ void *user_data)
+{
+ const struct mg_option *list;
+ const char *option_name, *option_value;
+ int i;
+
+ user_data = NULL; /* Unused */
+
+ (void) mg_printf(conn,
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n\r\n"
+ "<html><body><h1>Mongoose v. %s</h1>", mg_version());
+
+ if (!strcmp(ri->request_method, "POST")) {
+ option_name = mg_get_var(conn, "o");
+ option_value = mg_get_var(conn, "v");
+ if (mg_set_option(conn->ctx,
+ option_name, option_value) == -1) {
+ (void) mg_printf(conn,
+ "<p style=\"background: red\">Error setting "
+ "option \"%s\"</p>",
+ option_name ? option_name : "(null)");
+ } else {
+ (void) mg_printf(conn,
+ "<p style=\"color: green\">Saved: %s=%s</p>",
+ option_name, option_value ? option_value : "NULL");
+ }
+ }
+
+ /* Print table with all options */
+ list = mg_get_option_list();
+ (void) mg_printf(conn, "%s", "<table border=\"1\""
+ "<tr><th>Option</th><th>Description</th>"
+ "<th colspan=2>Value</th></tr>");
+
+ for (i = 0; list[i].name != NULL; i++) {
+ option_value = mg_get_option(conn->ctx, list[i].name);
+ if (option_value == NULL)
+ option_value = "";
+ (void) mg_printf(conn,
+ "<form method=post><tr><td>%s</td><td>%s</td>"
+ "<input type=hidden name=o value='%s'>"
+ "<td><input type=text name=v value='%s'></td>"
+ "<td><input type=submit value=save></td></form></tr>",
+ list[i].name, list[i].description, list[i].name,
+ option_value);
+ }
+
+ (void) mg_printf(conn, "%s", "</table></body></html>");
+}
+
+static bool_t
+set_admin_uri_option(struct mg_context *ctx, const char *uri)
+{
+ mg_bind_to_uri(ctx, uri, &admin_page, NULL);
+ return (TRUE);
+}
+
+static const struct mg_option known_options[] = {
+ {"root", "\tWeb root directory", NULL},
+ {"index_files", "Index files", "index.html,index.htm,index.cgi"},
+#if !defined(NO_SSL)
+ {"ssl_cert", "SSL certificate file", NULL},
+#endif /* !NO_SSL */
+ {"ports", "Listening ports", NULL},
+ {"dir_list", "Directory listing", "yes"},
+ {"protect", "URI to htpasswd mapping", NULL},
+#if !defined(NO_CGI)
+ {"cgi_ext", "CGI extensions", "cgi,pl,php"},
+ {"cgi_interp", "CGI interpreter to use with all CGI scripts", NULL},
+#endif /* NO_CGI */
+ {"ssi_ext", "SSI extensions", "shtml,shtm"},
+#if !defined(NO_AUTH)
+ {"auth_realm", "Authentication domain name", "mydomain.com"},
+ {"auth_gpass", "Global passwords file", NULL},
+ {"auth_PUT", "PUT,DELETE auth file", NULL},
+#endif /* !NO_AUTH */
+#if !defined(_WIN32)
+ {"uid", "\tRun as user", NULL},
+#endif /* !_WIN32 */
+ {"access_log", "Access log file", NULL},
+ {"error_log", "Error log file", NULL},
+ {"aliases", "Path=URI mappings", NULL},
+ {"admin_uri", "Administration page URI", NULL},
+ {"acl", "\tAllow/deny IP addresses/subnets", NULL},
+ {"threads", "Thread pool size", "5"},
+ {NULL, NULL, NULL}
+};
+
+static const struct option_setter {
+ int context_index;
+ bool_t (*setter)(struct mg_context *, const char *);
+} setters[] = {
+ {OPT_ROOT, NULL},
+ {OPT_INDEX_FILES, NULL},
+#if !defined(NO_SSL)
+ {OPT_SSL_CERTIFICATE, &set_ssl_option},
+#endif /* !NO_SSL */
+ {OPT_PORTS, &set_ports_option},
+ {OPT_DIR_LIST, NULL},
+ {OPT_PROTECT, NULL},
+#if !defined(NO_CGI)
+ {OPT_CGI_EXTENSIONS, NULL},
+ {OPT_CGI_INTERPRETER, NULL},
+#endif /* NO_CGI */
+ {OPT_SSI_EXTENSIONS, NULL},
+#if !defined(NO_AUTH)
+ {OPT_AUTH_DOMAIN, NULL},
+ {OPT_AUTH_GPASSWD, &set_gpass_option},
+ {OPT_AUTH_PUT, NULL},
+#endif /* !NO_AUTH */
+#if !defined(_WIN32)
+ {OPT_UID, &set_uid_option},
+#endif /* !_WIN32 */
+ {OPT_ACCESS_LOG, &set_alog_option},
+ {OPT_ERROR_LOG, &set_elog_option},
+ {OPT_ALIASES, NULL},
+ {OPT_ADMIN_URI, &set_admin_uri_option},
+ {OPT_ACL, NULL},
+ {OPT_THREADS, NULL},
+ {-1, NULL}
+};
+
+static const struct mg_option *
+find_opt(const char *opt_name)
+{
+ int i;
+
+ for (i = 0; known_options[i].name != NULL; i++)
+ if (!strcmp(opt_name, known_options[i].name))
+ return (known_options + i);
+
+ return (NULL);
+}
+
+int
+mg_set_option(struct mg_context *ctx, const char *opt, const char *val)
+{
+ const struct mg_option *option;
+ int i, ctx_index, retval;
+
+ mg_lock(ctx);
+ if (opt != NULL && (option = find_opt(opt)) != NULL) {
+ i = (int) (option - known_options);
+
+ if (setters[i].setter != NULL)
+ retval = setters[i].setter(ctx, val);
+ else
+ retval = TRUE;
+
+ /* Free old value if any */
+ ctx_index = setters[i].context_index;
+ if (ctx->options[ctx_index] != NULL)
+ free(ctx->options[ctx_index]);
+
+ /* Set new option value */
+ ctx->options[ctx_index] = val ? mg_strdup(val) : NULL;
+ } else {
+ retval = -1;
+ }
+ mg_unlock(ctx);
+
+ return (retval);
+}
+
+const struct mg_option *
+mg_get_option_list(void)
+{
+ return (known_options);
+}
+
+const char *
+mg_get_option(struct mg_context *ctx, const char *option_name)
+{
+ const struct mg_option *o;
+ const char *value = NULL;
+
+ mg_lock(ctx);
+ value = NULL;
+ if ((o = find_opt(option_name)) != NULL)
+ value = ctx->options[setters[o - known_options].context_index];
+ mg_unlock(ctx);
+
+ return (value);
+}
+
+static void
+reset_per_request_attributes(struct mg_connection *conn)
+{
+ if (conn->request_info.remote_user != NULL)
+ free(conn->request_info.remote_user);
+ if (conn->free_post_data && conn->request_info.post_data != NULL)
+ free((void *)conn->request_info.post_data);
+}
+
+static void
+close_socket_gracefully(SOCKET sock)
+{
+ char buf[BUFSIZ];
+ int n;
+
+ /* Send FIN to the client */
+ (void) shutdown(sock, SHUT_WR);
+
+ /*
+ * Read and discard pending data. If we do not do that and close the
+ * socket, the data in the send buffer may be discarded. This
+ * behaviour is seen on Windows, when client keeps sending data
+ * when server decide to close the connection; then when client
+ * does recv() it gets no data back.
+ */
+ do {
+ n = pull(-1, sock, NULL, buf, sizeof(buf));
+ } while (n > 0);
+
+ /* Now we know that our FIN is ACK-ed, safe to close */
+ (void) closesocket(sock);
+}
+
+static void
+close_connection(struct mg_connection *conn)
+{
+ reset_per_request_attributes(conn);
+ if (conn->ssl)
+ SSL_free(conn->ssl);
+ if (conn->sock != INVALID_SOCKET) {
+ close_socket_gracefully(conn->sock);
+ }
+}
+
+static void
+reset_connection_attributes(struct mg_connection *conn)
+{
+ reset_per_request_attributes(conn);
+ conn->free_post_data = FALSE;
+ conn->request_info.status_code = -1;
+ conn->keep_alive = FALSE;
+ conn->num_bytes_sent = 0;
+ (void) memset(&conn->request_info, 0, sizeof(conn->request_info));
+}
+
+static void
+shift_to_next(struct mg_connection *conn, char *buf, int req_len, int *nread)
+{
+ uint64_t cl;
+ int over_len, body_len;
+
+ cl = get_content_length(conn);
+ over_len = *nread - req_len;
+ assert(over_len >= 0);
+
+ if (cl == UNKNOWN_CONTENT_LENGTH) {
+ body_len = 0;
+ } else if (cl < (uint64_t) over_len) {
+ body_len = (int) cl;
+ } else {
+ body_len = over_len;
+ }
+
+ *nread -= req_len + body_len;
+ (void) memmove(buf, buf + req_len + body_len, *nread);
+}
+
+static void
+process_new_connection(struct mg_connection *conn)
+{
+ struct mg_request_info *ri = &conn->request_info;
+ char buf[MAX_REQUEST_SIZE];
+ int request_len, nread;
+
+ nread = 0;
+ do {
+ /* If next request is not pipelined, read it in */
+ if ((request_len = get_request_len(buf, (size_t) nread)) == 0)
+ request_len = read_request(-1, conn->sock, conn->ssl,
+ buf, sizeof(buf), &nread);
+ assert(nread >= request_len);
+
+ if (request_len == 0)
+ break; /* Remote end closed the connection */
+
+ /*
+ * This sets conn->keep_alive to FALSE, so by default
+ * we break the loop.
+ */
+ reset_connection_attributes(conn);
+
+ /* 0-terminate the request: parse_request uses sscanf */
+ buf[request_len - 1] = '\0';
+
+ if (parse_http_request(buf, ri, &conn->rsa)) {
+ if (ri->http_version_major != 1 ||
+ (ri->http_version_major == 1 &&
+ (ri->http_version_minor < 0 ||
+ ri->http_version_minor > 1))) {
+ send_error(conn, 505,
+ "HTTP version not supported",
+ "%s", "Weird HTTP version");
+ log_access(conn);
+ } else {
+ ri->post_data = buf + request_len;
+ ri->post_data_len = nread - request_len;
+ analyze_request(conn);
+ log_access(conn);
+ shift_to_next(conn, buf, request_len, &nread);
+ }
+ } else {
+ /* Do not put garbage in the access log */
+ send_error(conn, 400, "Bad Request",
+ "Can not parse request: [%.*s]", nread, buf);
+ }
+
+ } while (conn->keep_alive);
+}
+
+static void
+accept_new_connection(const struct socket *listener, struct mg_context *ctx)
+{
+ struct socket rem;
+
+ rem.usa.len = sizeof(rem.usa.u.sin);
+
+ if ((rem.sock = accept(listener->sock,
+ &rem.usa.u.sa, &rem.usa.len)) == -1) {
+ cry("accept: %d", ERRNO);
+ } else if (!check_acl(ctx, &rem.usa)) {
+ (void) closesocket(rem.sock);
+ cry("%s: denied by ACL", inet_ntoa(rem.usa.u.sin.sin_addr));
+ } else {
+ rem.is_ssl = listener->is_ssl;
+ put_socket(&ctx->socket_pool, &rem);
+ }
+}
+
+static void
+worker_loop(struct mg_context *ctx)
+{
+ struct mg_connection conn;
+ struct socket rem;
+
+ for (;;) {
+ get_socket(&ctx->socket_pool, &rem);
+ conn.sock = rem.sock;
+ conn.rsa = rem.usa;
+ conn.ctx = ctx;
+ conn.birth_time = time(NULL);
+
+ if (rem.is_ssl && (conn.ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
+ cry("%s: SSL_new: %s", __func__, strerror(ERRNO));
+ } else if (rem.is_ssl && SSL_set_fd(conn.ssl, conn.sock) != 1) {
+ cry("%s: SSL_set_fd: %s", __func__, strerror(ERRNO));
+ } else if (rem.is_ssl && SSL_accept(conn.ssl) != 1) {
+ cry("%s: SSL handshake failed", __func__);
+ } else {
+ process_new_connection(&conn);
+ }
+ close_connection(&conn);
+ }
+}
+
+static void
+listening_loop(struct mg_context *ctx)
+{
+ fd_set read_set;
+ struct timeval tv;
+ int i, max_fd;
+
+ while (ctx->stop_flag == 0) {
+ FD_ZERO(&read_set);
+ max_fd = -1;
+
+ /* Add listening sockets to the read set */
+ for (i = 0; i < ctx->num_listeners; i++)
+ add_to_set(ctx->listeners[i].sock, &read_set, &max_fd);
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
+#ifdef _WIN32
+ /*
+ * On windows, if read_set and write_set are empty,
+ * select() returns "Invalid parameter" error
+ * (at least on my Windows XP Pro). So in this case,
+ * we sleep here.
+ */
+ Sleep(1000);
+#endif /* _WIN32 */
+ } else {
+ for (i = 0; i < ctx->num_listeners; i++)
+ if (FD_ISSET(ctx->listeners[i].sock, &read_set))
+ accept_new_connection(
+ ctx->listeners + i, ctx);
+ }
+ }
+
+ /* Stop signal received: somebody called mg_stop. Quit. */
+ mg_fini(ctx);
+}
+
+void
+mg_stop(struct mg_context *ctx)
+{
+ ctx->stop_flag = 1;
+}
+
+struct mg_context *
+mg_start(void)
+{
+ struct mg_context *ctx;
+ int i;
+
+ if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
+ cry("cannot allocate mongoose context");
+ return (NULL);
+ }
+
+ /* Initialize options. First pass: set default option values */
+ for (i = 0; known_options[i].name != NULL; i++)
+ ctx->options[setters[i].context_index] =
+ known_options[i].default_value == NULL ?
+ NULL : mg_strdup(known_options[i].default_value);
+
+ /* Call setter functions */
+ for (i = 0; known_options[i].name != NULL; i++)
+ if (setters[i].setter &&
+ ctx->options[setters[i].context_index] != NULL)
+ if (setters[i].setter(ctx,
+ ctx->options[setters[i].context_index]) == FALSE) {
+ mg_fini(ctx);
+ return (NULL);
+ }
+
+ /* Initial document root is set to current working directory */
+ if (ctx->options[OPT_ROOT] == NULL)
+ ctx->options[OPT_ROOT] = getcwd(NULL, 0);
+
+#if 0
+ tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
+#endif
+
+#ifdef _WIN32
+ {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);}
+#endif /* _WIN32 */
+
+ /* Start worker threads */
+ init_socket_pool(&ctx->socket_pool);
+ for (i = 0; i < atoi(ctx->options[OPT_THREADS]); i++)
+ start_thread((mg_thread_func_t) worker_loop, ctx);
+
+ /* Start master (listening) thread */
+ (void) pthread_mutex_init(&ctx->mutex, NULL);
+ start_thread((mg_thread_func_t) listening_loop, ctx);
+
+ return (ctx);
+}
diff --git a/vendor/mongoose/mongoose.h b/vendor/mongoose/mongoose.h
new file mode 100644
index 0000000..102078b
--- /dev/null
+++ b/vendor/mongoose/mongoose.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2004-2009 Sergey Lyubka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef MONGOOSE_HEADER_INCLUDED
+#define MONGOOSE_HEADER_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct mg_context; /* Handle for the HTTP service itself */
+struct mg_connection; /* Handle for the individual connection */
+
+/*
+ * This structure contains full information about the HTTP request.
+ * It is passed to the user-specified callback function as a parameter.
+ */
+struct mg_request_info {
+ char *request_method; /* "GET", "POST", etc */
+ char *uri; /* Normalized URI */
+ char *query_string; /* \0 - terminated */
+ char *post_data; /* POST data buffer */
+ char *remote_user; /* Authenticated user */
+ long remote_ip; /* Client's IP address */
+ int remote_port; /* Client's port */
+ int post_data_len; /* POST buffer length */
+ int http_version_major;
+ int http_version_minor;
+ int status_code; /* HTTP status code */
+ int num_headers; /* Number of headers */
+#define MAX_HTTP_HEADERS 64
+ struct mg_header {
+ char *name; /* HTTP header name */
+ char *value; /* HTTP header value */
+ } http_headers[MAX_HTTP_HEADERS];
+};
+
+/*
+ * Mongoose configuration option.
+ * Array of those is returned by mg_get_option_list().
+ */
+struct mg_option {
+ char *name;
+ char *description;
+ char *default_value;
+};
+
+/*
+ * Functions dealing with initialization, starting and stopping Mongoose
+ *
+ * mg_start Start serving thread. Return server context.
+ * mg_stop Stop server thread, and release the context.
+ * mg_set_option Set an option for the running context.
+ * mg_get_option Get an option for the running context.
+ * mg_get_option_list Get a list of all known options.
+ * mg_handle_uri Associate user function with paticular URI.
+ * '*' in regex matches zero or more characters.
+ * mg_handle_error_code Associate user function with HTTP error code.
+ * Passing 0 as error code binds function to all codes.
+ * Error code is passed as status_code in request info.
+ * mg_protect_uri Similar to "protect" option, but uses a user
+ * specified function instead of the passwords file.
+ * User specified function is usual callback, which
+ * does use its third argument to pass the result back.
+ */
+
+struct mg_context *mg_start(void);
+void mg_stop(struct mg_context *);
+const struct mg_option *mg_get_option_list(void);
+const char *mg_get_option(struct mg_context *, const char *);
+int mg_set_option(struct mg_context *, const char *, const char *);
+
+typedef void (*mg_callback_t)(struct mg_connection *,
+ const struct mg_request_info *info, void *user_data);
+
+void mg_bind_to_uri(struct mg_context *ctx, const char *uri_regex,
+ mg_callback_t func, void *user_data);
+void mg_bind_to_error_code(struct mg_context *ctx, int error_code,
+ mg_callback_t func, void *user_data);
+void mg_protect_uri(struct mg_context *ctx, const char *uri_regex,
+ mg_callback_t func, void *user_data);
+
+/*
+ * Needed only if SSL certificate asks for a password.
+ * Instead of prompting for a password, specified function will be called.
+ */
+typedef int (*mg_spcb_t)(char *buf, int num, int w, void *key);
+void mg_set_ssl_password_callback(struct mg_context *ctx, mg_spcb_t func);
+
+/*
+ * Functions that can be used within the user URI callback
+ *
+ * mg_write Send data to the remote end.
+ * mg_printf Send data, using printf() semantics.
+ * mg_get_header Helper function to get HTTP header value
+ * mg_get_var Helper function to get form variable value.
+ * Returned value must be free-d by the caller.
+ */
+int mg_write(struct mg_connection *, const void *buf, int len);
+int mg_printf(struct mg_connection *, const char *fmt, ...);
+const char *mg_get_header(const struct mg_connection *, const char *hdr_name);
+char *mg_get_var(const struct mg_connection *, const char *var_name);
+
+/*
+ * General helper functions
+ * mg_version Return current version.
+ * mg_md5 Helper function. buf must be 33 bytes in size. Expects
+ * a NULL terminated list of asciz strings.
+ * Fills buf with stringified \0 terminated MD5 hash.
+ */
+const char *mg_version(void);
+void mg_md5(char *buf, ...);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* MONGOOSE_HEADER_INCLUDED */
diff --git a/vendor/shttpd/CMakeLists.txt b/vendor/shttpd/CMakeLists.txt
deleted file mode 100644
index 6c6c152..0000000
--- a/vendor/shttpd/CMakeLists.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-SET(shttp_SOURCES
- auth.c
- cgi.c
- compat_unix.c
- config.h
- defs.h
- io_cgi.c
- io_dir.c
- io_emb.c
- io_file.c
- io.h
- io_socket.c
- io_ssi.c
- io_ssl.c
- llist.h
- log.c
- md5.c
- md5.h
- shttpd.c
- shttpd.h
- ssl.h
- standalone.c
- std_includes.h
- string.c
-)
-
-ADD_LIBRARY(shttp ${shttp_SOURCES})
-TARGET_LINK_LIBRARIES(shttp dl pthread)
-
diff --git a/vendor/shttpd/auth.c b/vendor/shttpd/auth.c
deleted file mode 100644
index 85d1b4d..0000000
--- a/vendor/shttpd/auth.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-#if !defined(NO_AUTH)
-/*
- * Stringify binary data. Output buffer must be twice as big as input,
- * because each byte takes 2 bytes in string representation
- */
-static void
-bin2str(char *to, const unsigned char *p, size_t len)
-{
- const char *hex = "0123456789abcdef";
-
- for (;len--; p++) {
- *to++ = hex[p[0] >> 4];
- *to++ = hex[p[0] & 0x0f];
- }
-}
-
-/*
- * Return stringified MD5 hash for list of vectors.
- * buf must point to at least 32-bytes long buffer
- */
-static void
-md5(char *buf, ...)
-{
- unsigned char hash[16];
- const struct vec *v;
- va_list ap;
- MD5_CTX ctx;
- int i;
-
- MD5Init(&ctx);
-
- va_start(ap, buf);
- for (i = 0; (v = va_arg(ap, const struct vec *)) != NULL; i++) {
- assert(v->len >= 0);
- if (v->len == 0)
- continue;
- if (i > 0)
- MD5Update(&ctx, (unsigned char *) ":", 1);
- MD5Update(&ctx,(unsigned char *)v->ptr,(unsigned int)v->len);
- }
- va_end(ap);
-
- MD5Final(hash, &ctx);
- bin2str(buf, hash, sizeof(hash));
-}
-
-/*
- * Compare to vectors. Return 1 if they are equal
- */
-static int
-vcmp(const struct vec *v1, const struct vec *v2)
-{
- return (v1->len == v2->len && !memcmp(v1->ptr, v2->ptr, v1->len));
-}
-
-struct digest {
- struct vec user;
- struct vec uri;
- struct vec nonce;
- struct vec cnonce;
- struct vec resp;
- struct vec qop;
- struct vec nc;
-};
-
-static const struct auth_keyword {
- size_t offset;
- struct vec vec;
-} known_auth_keywords[] = {
- {offsetof(struct digest, user), {"username=", 9}},
- {offsetof(struct digest, cnonce), {"cnonce=", 7}},
- {offsetof(struct digest, resp), {"response=", 9}},
- {offsetof(struct digest, uri), {"uri=", 4}},
- {offsetof(struct digest, qop), {"qop=", 4}},
- {offsetof(struct digest, nc), {"nc=", 3}},
- {offsetof(struct digest, nonce), {"nonce=", 6}},
- {0, {NULL, 0}}
-};
-
-static void
-parse_authorization_header(const struct vec *h, struct digest *dig)
-{
- const unsigned char *p, *e, *s;
- struct vec *v, vec;
- const struct auth_keyword *kw;
-
- (void) memset(dig, 0, sizeof(*dig));
- p = (unsigned char *) h->ptr + 7;
- e = (unsigned char *) h->ptr + h->len;
-
- while (p < e) {
-
- /* Skip spaces */
- while (p < e && (*p == ' ' || *p == ','))
- p++;
-
- /* Skip to "=" */
- for (s = p; s < e && *s != '='; )
- s++;
- s++;
-
- /* Is it known keyword ? */
- for (kw = known_auth_keywords; kw->vec.len > 0; kw++)
- if (kw->vec.len <= s - p &&
- !memcmp(p, kw->vec.ptr, kw->vec.len))
- break;
-
- if (kw->vec.len == 0)
- v = &vec; /* Dummy placeholder */
- else
- v = (struct vec *) ((char *) dig + kw->offset);
-
- if (*s == '"') {
- p = ++s;
- while (p < e && *p != '"')
- p++;
- } else {
- p = s;
- while (p < e && *p != ' ' && *p != ',')
- p++;
- }
-
- v->ptr = (char *) s;
- v->len = p - s;
-
- if (*p == '"')
- p++;
-
- DBG(("auth field [%.*s]", v->len, v->ptr));
- }
-}
-
-/*
- * Check the user's password, return 1 if OK
- */
-static int
-check_password(int method, const struct vec *ha1, const struct digest *digest)
-{
- char a2[32], resp[32];
- struct vec vec_a2;
-
- /* XXX Due to a bug in MSIE, we do not compare the URI */
- /* Also, we do not check for authentication timeout */
- if (/*strcmp(dig->uri, c->ouri) != 0 || */
- digest->resp.len != 32 /*||
- now - strtoul(dig->nonce, NULL, 10) > 3600 */)
- return (0);
-
- md5(a2, &_shttpd_known_http_methods[method], &digest->uri, NULL);
- vec_a2.ptr = a2;
- vec_a2.len = sizeof(a2);
- md5(resp, ha1, &digest->nonce, &digest->nc,
- &digest->cnonce, &digest->qop, &vec_a2, NULL);
- DBG(("%s: uri [%.*s] expected_resp [%.*s] resp [%.*s]",
- "check_password", digest->uri.len, digest->uri.ptr,
- 32, resp, digest->resp.len, digest->resp.ptr));
-
- return (!memcmp(resp, digest->resp.ptr, 32));
-}
-
-static FILE *
-open_auth_file(struct shttpd_ctx *ctx, const char *path)
-{
- char name[FILENAME_MAX];
- const char *p, *e;
- FILE *fp = NULL;
- int fd;
-
- if (ctx->options[OPT_AUTH_GPASSWD] != NULL) {
- /* Use global passwords file */
- _shttpd_snprintf(name, sizeof(name), "%s",
- ctx->options[OPT_AUTH_GPASSWD]);
- } else {
- /*
- * Try to find .htpasswd in requested directory.
- * Given the path, create the path to .htpasswd file
- * in the same directory. Find the right-most
- * directory separator character first. That would be the
- * directory name. If directory separator character is not
- * found, 'e' will point to 'p'.
- */
- for (p = path, e = p + strlen(p) - 1; e > p; e--)
- if (IS_DIRSEP_CHAR(*e))
- break;
-
- /*
- * Make up the path by concatenating directory name and
- * .htpasswd file name.
- */
- (void) _shttpd_snprintf(name, sizeof(name), "%.*s/%s",
- (int) (e - p), p, HTPASSWD);
- }
-
- if ((fd = _shttpd_open(name, O_RDONLY, 0)) == -1) {
- DBG(("open_auth_file: open(%s)", name));
- } else if ((fp = fdopen(fd, "r")) == NULL) {
- DBG(("open_auth_file: fdopen(%s)", name));
- (void) close(fd);
- }
-
- return (fp);
-}
-
-/*
- * Parse the line from htpasswd file. Line should be in form of
- * "user:domain:ha1". Fill in the vector values. Return 1 if successful.
- */
-static int
-parse_htpasswd_line(const char *s, struct vec *user,
- struct vec *domain, struct vec *ha1)
-{
- user->len = domain->len = ha1->len = 0;
-
- for (user->ptr = s; *s != '\0' && *s != ':'; s++, user->len++);
- if (*s++ != ':')
- return (0);
-
- for (domain->ptr = s; *s != '\0' && *s != ':'; s++, domain->len++);
- if (*s++ != ':')
- return (0);
-
- for (ha1->ptr = s; *s != '\0' && !isspace(* (unsigned char *) s);
- s++, ha1->len++);
-
- DBG(("parse_htpasswd_line: [%.*s] [%.*s] [%.*s]", user->len, user->ptr,
- domain->len, domain->ptr, ha1->len, ha1->ptr));
-
- return (user->len > 0 && domain->len > 0 && ha1->len > 0);
-}
-
-/*
- * Authorize against the opened passwords file. Return 1 if authorized.
- */
-static int
-authorize(struct conn *c, FILE *fp)
-{
- struct vec *auth_vec = &c->ch.auth.v_vec;
- struct vec *user_vec = &c->ch.user.v_vec;
- struct vec user, domain, ha1;
- struct digest digest;
- int ok = 0;
- char line[256];
-
- if (auth_vec->len > 20 &&
- !_shttpd_strncasecmp(auth_vec->ptr, "Digest ", 7)) {
-
- parse_authorization_header(auth_vec, &digest);
- *user_vec = digest.user;
-
- while (fgets(line, sizeof(line), fp) != NULL) {
-
- if (!parse_htpasswd_line(line, &user, &domain, &ha1))
- continue;
-
- DBG(("[%.*s] [%.*s] [%.*s]", user.len, user.ptr,
- domain.len, domain.ptr, ha1.len, ha1.ptr));
-
- if (vcmp(user_vec, &user) &&
- !memcmp(c->ctx->options[OPT_AUTH_REALM],
- domain.ptr, domain.len)) {
- ok = check_password(c->method, &ha1, &digest);
- break;
- }
- }
- }
-
- return (ok);
-}
-
-int
-_shttpd_check_authorization(struct conn *c, const char *path)
-{
- FILE *fp = NULL;
- int len, n, authorized = 1;
- const char *p, *s = c->ctx->options[OPT_PROTECT];
- char protected_path[FILENAME_MAX];
-
- FOR_EACH_WORD_IN_LIST(s, len) {
-
- if ((p = memchr(s, '=', len)) == NULL || p >= s + len || p == s)
- continue;
-
- if (!memcmp(c->uri, s, p - s)) {
-
- n = s + len - p;
- if (n > (int) sizeof(protected_path) - 1)
- n = sizeof(protected_path) - 1;
-
- _shttpd_strlcpy(protected_path, p + 1, n);
-
- if ((fp = fopen(protected_path, "r")) == NULL)
- _shttpd_elog(E_LOG, c,
- "check_auth: cannot open %s: %s",
- protected_path, strerror(errno));
- break;
- }
- }
-
- if (fp == NULL)
- fp = open_auth_file(c->ctx, path);
-
- if (fp != NULL) {
- authorized = authorize(c, fp);
- (void) fclose(fp);
- }
-
- return (authorized);
-}
-
-int
-_shttpd_is_authorized_for_put(struct conn *c)
-{
- FILE *fp;
- int ret = 0;
-
- if ((fp = fopen(c->ctx->options[OPT_AUTH_PUT], "r")) != NULL) {
- ret = authorize(c, fp);
- (void) fclose(fp);
- }
-
- return (ret);
-}
-
-void
-_shttpd_send_authorization_request(struct conn *c)
-{
- char buf[512];
-
- (void) _shttpd_snprintf(buf, sizeof(buf), "Unauthorized\r\n"
- "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
- "nonce=\"%lu\"", c->ctx->options[OPT_AUTH_REALM],
- (unsigned long) _shttpd_current_time);
-
- _shttpd_send_server_error(c, 401, buf);
-}
-
-/*
- * Edit the passwords file.
- */
-int
-_shttpd_edit_passwords(const char *fname, const char *domain,
- const char *user, const char *pass)
-{
- int ret = EXIT_SUCCESS, found = 0;
- struct vec u, d, p;
- char line[512], tmp[FILENAME_MAX], ha1[32];
- FILE *fp = NULL, *fp2 = NULL;
-
- (void) _shttpd_snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
-
- /* Create the file if does not exist */
- if ((fp = fopen(fname, "a+")))
- (void) fclose(fp);
-
- /* Open the given file and temporary file */
- if ((fp = fopen(fname, "r")) == NULL)
- _shttpd_elog(E_FATAL, NULL,
- "Cannot open %s: %s", fname, strerror(errno));
- else if ((fp2 = fopen(tmp, "w+")) == NULL)
- _shttpd_elog(E_FATAL, NULL,
- "Cannot open %s: %s", tmp, strerror(errno));
-
- p.ptr = pass;
- p.len = strlen(pass);
-
- /* Copy the stuff to temporary file */
- while (fgets(line, sizeof(line), fp) != NULL) {
- u.ptr = line;
- if ((d.ptr = strchr(line, ':')) == NULL)
- continue;
- u.len = d.ptr - u.ptr;
- d.ptr++;
- if (strchr(d.ptr, ':') == NULL)
- continue;
- d.len = strchr(d.ptr, ':') - d.ptr;
-
- if ((int) strlen(user) == u.len &&
- !memcmp(user, u.ptr, u.len) &&
- (int) strlen(domain) == d.len &&
- !memcmp(domain, d.ptr, d.len)) {
- found++;
- md5(ha1, &u, &d, &p, NULL);
- (void) fprintf(fp2, "%s:%s:%.32s\n", user, domain, ha1);
- } else {
- (void) fprintf(fp2, "%s", line);
- }
- }
-
- /* If new user, just add it */
- if (found == 0) {
- u.ptr = user; u.len = strlen(user);
- d.ptr = domain; d.len = strlen(domain);
- md5(ha1, &u, &d, &p, NULL);
- (void) fprintf(fp2, "%s:%s:%.32s\n", user, domain, ha1);
- }
-
- /* Close files */
- (void) fclose(fp);
- (void) fclose(fp2);
-
- /* Put the temp file in place of real file */
- (void) _shttpd_remove(fname);
- (void) _shttpd_rename(tmp, fname);
-
- return (ret);
-}
-#endif /* NO_AUTH */
diff --git a/vendor/shttpd/cgi.c b/vendor/shttpd/cgi.c
deleted file mode 100644
index 1bdfbad..0000000
--- a/vendor/shttpd/cgi.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-#if !defined(NO_CGI)
-struct env_block {
- char buf[ENV_MAX]; /* Environment buffer */
- int len; /* Space taken */
- char *vars[CGI_ENV_VARS]; /* Point into the buffer */
- int nvars; /* Number of variables */
-};
-
-static void
-addenv(struct env_block *block, const char *fmt, ...)
-{
- int n, space;
- va_list ap;
-
- space = sizeof(block->buf) - block->len - 2;
- assert(space >= 0);
-
- va_start(ap, fmt);
- n = vsnprintf(block->buf + block->len, space, fmt, ap);
- va_end(ap);
-
- if (n > 0 && n < space && block->nvars < CGI_ENV_VARS - 2) {
- block->vars[block->nvars++] = block->buf + block->len;
- block->len += n + 1; /* Include \0 terminator */
- }
-}
-
-static void
-add_http_headers_to_env(struct env_block *b, const char *s, int len)
-{
- const char *p, *v, *e = s + len;
- int space, n, i, ch;
-
- /* Loop through all headers in the request */
- while (s < e) {
-
- /* Find where this header ends. Remember where value starts */
- for (p = s, v = NULL; p < e && *p != '\n'; p++)
- if (v == NULL && *p == ':')
- v = p;
-
- /* 2 null terminators and "HTTP_" */
- space = (sizeof(b->buf) - b->len) - (2 + 5);
- assert(space >= 0);
-
- /* Copy header if enough space in the environment block */
- if (v > s && p > v + 2 && space > p - s) {
-
- /* Store var */
- if (b->nvars < (int) NELEMS(b->vars) - 1)
- b->vars[b->nvars++] = b->buf + b->len;
-
- (void) memcpy(b->buf + b->len, "HTTP_", 5);
- b->len += 5;
-
- /* Copy header name. Substitute '-' to '_' */
- n = v - s;
- for (i = 0; i < n; i++) {
- ch = s[i] == '-' ? '_' : s[i];
- b->buf[b->len++] = toupper(ch);
- }
-
- b->buf[b->len++] = '=';
-
- /* Copy header value */
- v += 2;
- n = p[-1] == '\r' ? (p - v) - 1 : p - v;
- for (i = 0; i < n; i++)
- b->buf[b->len++] = v[i];
-
- /* Null-terminate */
- b->buf[b->len++] = '\0';
- }
-
- s = p + 1; /* Shift to the next header */
- }
-}
-
-static void
-prepare_environment(const struct conn *c, const char *prog,
- struct env_block *blk)
-{
- const struct headers *h = &c->ch;
- const char *s, *fname, *root = c->ctx->options[OPT_ROOT];
- size_t len;
-
- blk->len = blk->nvars = 0;
-
- /* SCRIPT_FILENAME */
- fname = prog;
- if ((s = strrchr(prog, '/')))
- fname = s + 1;
-
- /* Prepare the environment block */
- addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
- addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
- addenv(blk, "%s", "REDIRECT_STATUS=200"); /* PHP */
- addenv(blk, "SERVER_PORT=%d", c->loc_port);
- addenv(blk, "SERVER_NAME=%s", c->ctx->options[OPT_AUTH_REALM]);
- addenv(blk, "SERVER_ROOT=%s", root);
- addenv(blk, "DOCUMENT_ROOT=%s", root);
- addenv(blk, "REQUEST_METHOD=%s",
- _shttpd_known_http_methods[c->method].ptr);
- addenv(blk, "REMOTE_ADDR=%s", inet_ntoa(c->sa.u.sin.sin_addr));
- addenv(blk, "REMOTE_PORT=%hu", ntohs(c->sa.u.sin.sin_port));
- addenv(blk, "REQUEST_URI=%s", c->uri);
- addenv(blk, "SCRIPT_NAME=%s", prog + strlen(root));
- addenv(blk, "SCRIPT_FILENAME=%s", fname); /* PHP */
- addenv(blk, "PATH_TRANSLATED=%s", prog);
-
- if (h->ct.v_vec.len > 0)
- addenv(blk, "CONTENT_TYPE=%.*s",
- h->ct.v_vec.len, h->ct.v_vec.ptr);
-
- if (c->query != NULL)
- addenv(blk, "QUERY_STRING=%s", c->query);
-
- if (c->path_info != NULL)
- addenv(blk, "PATH_INFO=/%s", c->path_info);
-
- if (h->cl.v_big_int > 0)
- addenv(blk, "CONTENT_LENGTH=%lu", h->cl.v_big_int);
-
- if ((s = getenv("PATH")) != NULL)
- addenv(blk, "PATH=%s", s);
-
-#ifdef _WIN32
- if ((s = getenv("COMSPEC")) != NULL)
- addenv(blk, "COMSPEC=%s", s);
- if ((s = getenv("SYSTEMROOT")) != NULL)
- addenv(blk, "SYSTEMROOT=%s", s);
-#else
- if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
- addenv(blk, "LD_LIBRARY_PATH=%s", s);
-#endif /* _WIN32 */
-
- if ((s = getenv("PERLLIB")) != NULL)
- addenv(blk, "PERLLIB=%s", s);
-
- if (h->user.v_vec.len > 0) {
- addenv(blk, "REMOTE_USER=%.*s",
- h->user.v_vec.len, h->user.v_vec.ptr);
- addenv(blk, "%s", "AUTH_TYPE=Digest");
- }
-
- /* Add user-specified variables */
- s = c->ctx->options[OPT_CGI_ENVIRONMENT];
- FOR_EACH_WORD_IN_LIST(s, len)
- addenv(blk, "%.*s", len, s);
-
- /* Add all headers as HTTP_* variables */
- add_http_headers_to_env(blk, c->headers,
- c->rem.headers_len - (c->headers - c->request));
-
- blk->vars[blk->nvars++] = NULL;
- blk->buf[blk->len++] = '\0';
-
- assert(blk->nvars < CGI_ENV_VARS);
- assert(blk->len > 0);
- assert(blk->len < (int) sizeof(blk->buf));
-
- /* Debug stuff to view passed environment */
- DBG(("%s: %d vars, %d env size", prog, blk->nvars, blk->len));
- {
- int i;
- for (i = 0 ; i < blk->nvars; i++)
- DBG(("[%s]", blk->vars[i] ? blk->vars[i] : "null"));
- }
-}
-
-int
-_shttpd_run_cgi(struct conn *c, const char *prog)
-{
- struct env_block blk;
- char dir[FILENAME_MAX], *p;
- int ret, pair[2];
-
- prepare_environment(c, prog, &blk);
- pair[0] = pair[1] = -1;
-
- /* CGI must be executed in its own directory */
- (void) _shttpd_snprintf(dir, sizeof(dir), "%s", prog);
- for (p = dir + strlen(dir) - 1; p > dir; p--)
- if (*p == '/') {
- *p++ = '\0';
- break;
- }
-
- if (shttpd_socketpair(pair) != 0) {
- ret = -1;
- } else if (_shttpd_spawn_process(c,
- prog, blk.buf, blk.vars, pair[1], dir)) {
- ret = -1;
- (void) closesocket(pair[0]);
- (void) closesocket(pair[1]);
- } else {
- ret = 0;
- c->loc.chan.sock = pair[0];
- }
-
- return (ret);
-}
-
-void
-_shttpd_do_cgi(struct conn *c)
-{
- DBG(("running CGI: [%s]", c->uri));
- assert(c->loc.io.size > CGI_REPLY_LEN);
- memcpy(c->loc.io.buf, CGI_REPLY, CGI_REPLY_LEN);
- c->loc.io.head = c->loc.io.tail = c->loc.io.total = CGI_REPLY_LEN;
- c->loc.io_class = &_shttpd_io_cgi;
- c->loc.flags = FLAG_R;
- if (c->method == METHOD_POST)
- c->loc.flags |= FLAG_W;
-}
-
-#endif /* !NO_CGI */
diff --git a/vendor/shttpd/compat_rtems.c b/vendor/shttpd/compat_rtems.c
deleted file mode 100644
index 2a01a07..0000000
--- a/vendor/shttpd/compat_rtems.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/**********************************************************************
- *
- * rtems shttpd management
- *
- * FILE NAME : rtems_shttpd.c
- *
- * AUTHOR : Steven Johnson
- *
- * DESCRIPTION : Defines the interface functions to the shttp daemon
- *
- * REVISION : $Id: compat_rtems.c,v 1.2 2006/11/12 03:29:17 infidel Exp $
- *
- * COMMENTS :
- *
- **********************************************************************/
-
- /**********************************************************************
- * INCLUDED MODULES
- **********************************************************************/
-#include <rtems.h>
-#include "defs.h"
-
-#define MAX_WEB_BASE_PATH_LENGTH 256
-#define MIN_SHTTPD_STACK (8*1024)
-
-typedef struct RTEMS_HTTPD_ARGS {
- rtems_shttpd_init init_callback;
- rtems_shttpd_addpages addpages_callback;
- char webroot[MAX_WEB_BASE_PATH_LENGTH];
-} RTEMS_HTTPD_ARGS;
-
-static int rtems_webserver_running = FALSE; //not running.
-
-static rtems_task rtems_httpd_daemon(rtems_task_argument args )
-{
- RTEMS_HTTPD_ARGS *httpd_args = (RTEMS_HTTPD_ARGS*)args;
-
- struct shttpd_ctx *ctx;
-
- if (httpd_args != NULL)
- if (httpd_args->init_callback != NULL)
- httpd_args->init_callback();
-
-/**************************************
- * Initialize the web server
- */
- /*
- * Initialize SHTTPD context.
- * Set WWW root to current WEB_ROOT_PATH.
- */
- ctx = shttpd_init(NULL, "document_root", httpd_args->webroot, NULL);
-
- if (httpd_args != NULL)
- if (httpd_args->addpages_callback != NULL)
- httpd_args->addpages_callback(ctx);
-
- /* Finished with args, so free them */
- if (httpd_args != NULL)
- free(httpd_args);
-
- /* Open listening socket */
- shttpd_listen(ctx, 9000);
-
- rtems_webserver_running = TRUE;
-
- /* Serve connections infinitely until someone kills us */
- while (rtems_webserver_running)
- shttpd_poll(ctx, 1000);
-
- /* Unreached, because we will be killed by a signal */
- shttpd_fini(ctx);
-
- rtems_task_delete( RTEMS_SELF );
-}
-
-rtems_status_code rtems_initialize_webserver(rtems_task_priority initial_priority,
- rtems_unsigned32 stack_size,
- rtems_mode initial_modes,
- rtems_attribute attribute_set,
- rtems_shttpd_init init_callback,
- rtems_shttpd_addpages addpages_callback,
- char *webroot
- )
-{
- rtems_status_code sc;
- rtems_id tid;
- RTEMS_HTTPD_ARGS *args;
-
- if (stack_size < MIN_SHTTPD_STACK)
- stack_size = MIN_SHTTPD_STACK;
-
- args = malloc(sizeof(RTEMS_HTTPD_ARGS));
-
- if (args != NULL)
- {
- args->init_callback = init_callback;
- args->addpages_callback = addpages_callback;
- strncpy(args->webroot,webroot,MAX_WEB_BASE_PATH_LENGTH);
-
- sc = rtems_task_create(rtems_build_name('H', 'T', 'P', 'D'),
- initial_priority,
- stack_size,
- initial_modes,
- attribute_set,
- &tid);
-
- if (sc == RTEMS_SUCCESSFUL)
- {
- sc = rtems_task_start(tid, rtems_httpd_daemon, (rtems_task_argument)args);
- }
- }
- else
- {
- sc = RTEMS_NO_MEMORY;
- }
-
- return sc;
-}
-
-void rtems_terminate_webserver(void)
-{
- rtems_webserver_running = FALSE; //not running, so terminate
-}
-
-int rtems_webserver_ok(void)
-{
- return rtems_webserver_running;
-}
-
-void
-set_close_on_exec(int fd)
-{
- // RTEMS Does not have a functional "execve"
- // so technically this call does not do anything,
- // but it doesnt hurt either.
- (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
-}
-
-int
-my_stat(const char *path, struct stat *stp)
-{
- return (stat(path, stp));
-}
-
-int
-my_open(const char *path, int flags, int mode)
-{
- return (open(path, flags, mode));
-}
-
-int
-my_remove(const char *path)
-{
- return (remove(path));
-}
-
-int
-my_rename(const char *path1, const char *path2)
-{
- return (rename(path1, path2));
-}
-
-int
-my_mkdir(const char *path, int mode)
-{
- return (mkdir(path, mode));
-}
-
-char *
-my_getcwd(char *buffer, int maxlen)
-{
- return (getcwd(buffer, maxlen));
-}
-
-int
-set_non_blocking_mode(int fd)
-{
- int ret = -1;
- int flags;
-
- if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
- DBG(("nonblock: fcntl(F_GETFL): %d", ERRNO));
- } else if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
- DBG(("nonblock: fcntl(F_SETFL): %d", ERRNO));
- } else {
- ret = 0; /* Success */
- }
-
- return (ret);
-}
-
-#if !defined(NO_CGI)
-int
-spawn_process(struct conn *c, const char *prog, char *envblk, char **envp)
-{
- return (-1); // RTEMS does not have subprocess support as standard.
-}
-#endif
diff --git a/vendor/shttpd/compat_rtems.h b/vendor/shttpd/compat_rtems.h
deleted file mode 100644
index 8d31e46..0000000
--- a/vendor/shttpd/compat_rtems.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * @file rtems/rtems-shttpd.h
- */
-
-#ifndef _rtems_rtems_webserver_h
-#define _rtems_rtems_webserver_h
-
-#include "shttpd.h"
-
-#include <rtems.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <dirent.h>
-
-/* RTEMS is an Real Time Embedded operating system, for operation in hardware.
- It does not have SSL or CGI support, as it does not have dynamic library
- loading or sub-processes. */
-#define EMBEDDED
-#define NO_SSL
-#define NO_CGI
-
-#define DIRSEP '/'
-#define O_BINARY 0
-#define ERRNO errno
-
-/* RTEMS version is Thread Safe */
-#define InitializeCriticalSection(x) rtems_semaphore_create( \
- rtems_build_name('H','T','P','X'), \
- 1, /* Not Held Yet.*/ \
- RTEMS_FIFO | \
- RTEMS_BINARY_SEMAPHORE, \
- 0, \
- x);
-#define EnterCriticalSection(x) rtems_semaphore_obtain(*(x),RTEMS_WAIT,RTEMS_NO_TIMEOUT)
-#define LeaveCriticalSection(x) rtems_semaphore_release(*(x))
-
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void (*rtems_shttpd_addpages)(struct shttpd_ctx *ctx);
-typedef void (*rtems_shttpd_init)(void);
-
-rtems_status_code rtems_initialize_webserver(rtems_task_priority initial_priority,
- rtems_unsigned32 stack_size,
- rtems_mode initial_modes,
- rtems_attribute attribute_set,
- rtems_shttpd_init init_callback,
- rtems_shttpd_addpages addpages_callback,
- char *webroot
- );
-void rtems_terminate_webserver(void);
-int rtems_webserver_ok(void);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/vendor/shttpd/compat_unix.c b/vendor/shttpd/compat_unix.c
deleted file mode 100644
index e8fe929..0000000
--- a/vendor/shttpd/compat_unix.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-void
-_shttpd_set_close_on_exec(int fd)
-{
- (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
-}
-
-int
-_shttpd_stat(const char *path, struct stat *stp)
-{
- return (stat(path, stp));
-}
-
-int
-_shttpd_open(const char *path, int flags, int mode)
-{
- return (open(path, flags, mode));
-}
-
-int
-_shttpd_remove(const char *path)
-{
- return (remove(path));
-}
-
-int
-_shttpd_rename(const char *path1, const char *path2)
-{
- return (rename(path1, path2));
-}
-
-int
-_shttpd_mkdir(const char *path, int mode)
-{
- return (mkdir(path, mode));
-}
-
-char *
-_shttpd_getcwd(char *buffer, int maxlen)
-{
- return (getcwd(buffer, maxlen));
-}
-
-int
-_shttpd_set_non_blocking_mode(int fd)
-{
- int ret = -1;
- int flags;
-
- if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
- DBG(("nonblock: fcntl(F_GETFL): %d", ERRNO));
- } else if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
- DBG(("nonblock: fcntl(F_SETFL): %d", ERRNO));
- } else {
- ret = 0; /* Success */
- }
-
- return (ret);
-}
-
-#ifndef NO_CGI
-int
-_shttpd_spawn_process(struct conn *c, const char *prog, char *envblk,
- char *envp[], int sock, const char *dir)
-{
- int ret;
- pid_t pid;
- const char *p, *interp = c->ctx->options[OPT_CGI_INTERPRETER];
-
- envblk = NULL; /* unused */
-
- if ((pid = vfork()) == -1) {
-
- ret = -1;
- _shttpd_elog(E_LOG, c, "redirect: fork: %s", strerror(errno));
-
- } else if (pid == 0) {
-
- /* Child */
-
- (void) chdir(dir);
- (void) dup2(sock, 0);
- (void) dup2(sock, 1);
- (void) closesocket(sock);
-
- /* If error file is specified, send errors there */
- if (c->ctx->error_log)
- (void) dup2(fileno(c->ctx->error_log), 2);
-
- if ((p = strrchr(prog, '/')) != NULL)
- p++;
- else
- p = prog;
-
- /* Execute CGI program */
- if (interp == NULL) {
- (void) execle(p, p, NULL, envp);
- _shttpd_elog(E_FATAL, c, "redirect: exec(%s)", prog);
- } else {
- (void) execle(interp, interp, p, NULL, envp);
- _shttpd_elog(E_FATAL, c, "redirect: exec(%s %s)",
- interp, prog);
- }
-
- /* UNREACHED */
- exit(EXIT_FAILURE);
-
- } else {
-
- /* Parent */
- ret = 0;
- (void) closesocket(sock);
- }
-
- return (ret);
-}
-#endif /* !NO_CGI */
diff --git a/vendor/shttpd/compat_unix.h b/vendor/shttpd/compat_unix.h
deleted file mode 100644
index 53c7f03..0000000
--- a/vendor/shttpd/compat_unix.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2004-2007 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/mman.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/time.h>
-
-#include <pwd.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <dlfcn.h>
-
-#if !defined(NO_THREADS)
-#include "pthread.h"
-#define _beginthread(a, b, c) do { pthread_t tid; \
- pthread_create(&tid, NULL, (void *(*)(void *))a, c); } while (0)
-#endif /* !NO_THREADS */
-
-#define SSL_LIB "libssl.so"
-#define DIRSEP '/'
-#define IS_DIRSEP_CHAR(c) ((c) == '/')
-#define O_BINARY 0
-#define closesocket(a) close(a)
-#define ERRNO errno
diff --git a/vendor/shttpd/compat_win32.c b/vendor/shttpd/compat_win32.c
deleted file mode 100644
index d3b740a..0000000
--- a/vendor/shttpd/compat_win32.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-static SERVICE_STATUS ss;
-static SERVICE_STATUS_HANDLE hStatus;
-static SERVICE_DESCRIPTION service_descr = {"Web server"};
-
-static void
-fix_directory_separators(char *path)
-{
- for (; *path != '\0'; path++) {
- if (*path == '/')
- *path = '\\';
- if (*path == '\\')
- while (path[1] == '\\' || path[1] == '/')
- (void) memmove(path + 1,
- path + 2, strlen(path + 2) + 1);
- }
-}
-
-static int
-protect_against_code_disclosure(const wchar_t *path)
-{
- WIN32_FIND_DATAW data;
- HANDLE handle;
- const wchar_t *p;
-
- /*
- * Protect against CGI code disclosure under Windows.
- * This is very nasty hole. Windows happily opens files with
- * some garbage in the end of file name. So fopen("a.cgi ", "r")
- * actually opens "a.cgi", and does not return an error! And since
- * "a.cgi " does not have valid CGI extension, this leads to
- * the CGI code disclosure.
- * To protect, here we delete all fishy characters from the
- * end of file name.
- */
-
- if ((handle = FindFirstFileW(path, &data)) == INVALID_HANDLE_VALUE)
- return (FALSE);
-
- FindClose(handle);
-
- for (p = path + wcslen(path); p > path && p[-1] != L'\\';)
- p--;
-
- if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
- wcscmp(data.cFileName, p) != 0)
- return (FALSE);
-
- return (TRUE);
-}
-
-int
-_shttpd_open(const char *path, int flags, int mode)
-{
- char buf[FILENAME_MAX];
- wchar_t wbuf[FILENAME_MAX];
-
- _shttpd_strlcpy(buf, path, sizeof(buf));
- fix_directory_separators(buf);
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
-
- if (protect_against_code_disclosure(wbuf) == FALSE)
- return (-1);
-
- return (_wopen(wbuf, flags));
-}
-
-int
-_shttpd_stat(const char *path, struct stat *stp)
-{
- char buf[FILENAME_MAX], *p;
- wchar_t wbuf[FILENAME_MAX];
-
- _shttpd_strlcpy(buf, path, sizeof(buf));
- fix_directory_separators(buf);
-
- p = buf + strlen(buf) - 1;
- while (p > buf && *p == '\\' && p[-1] != ':')
- *p-- = '\0';
-
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
-
- return (_wstat(wbuf, (struct _stat *) stp));
-}
-
-int
-_shttpd_remove(const char *path)
-{
- char buf[FILENAME_MAX];
- wchar_t wbuf[FILENAME_MAX];
-
- _shttpd_strlcpy(buf, path, sizeof(buf));
- fix_directory_separators(buf);
-
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
-
- return (_wremove(wbuf));
-}
-
-int
-_shttpd_rename(const char *path1, const char *path2)
-{
- char buf1[FILENAME_MAX];
- char buf2[FILENAME_MAX];
- wchar_t wbuf1[FILENAME_MAX];
- wchar_t wbuf2[FILENAME_MAX];
-
- _shttpd_strlcpy(buf1, path1, sizeof(buf1));
- _shttpd_strlcpy(buf2, path2, sizeof(buf2));
- fix_directory_separators(buf1);
- fix_directory_separators(buf2);
-
- MultiByteToWideChar(CP_UTF8, 0, buf1, -1, wbuf1, sizeof(wbuf1));
- MultiByteToWideChar(CP_UTF8, 0, buf2, -1, wbuf2, sizeof(wbuf2));
-
- return (_wrename(wbuf1, wbuf2));
-}
-
-int
-_shttpd_mkdir(const char *path, int mode)
-{
- char buf[FILENAME_MAX];
- wchar_t wbuf[FILENAME_MAX];
-
- _shttpd_strlcpy(buf, path, sizeof(buf));
- fix_directory_separators(buf);
-
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
-
- return (_wmkdir(wbuf));
-}
-
-static char *
-wide_to_utf8(const wchar_t *str)
-{
- char *buf = NULL;
- if (str) {
- int nchar = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
- if (nchar > 0) {
- buf = malloc(nchar);
- if (!buf)
- errno = ENOMEM;
- else if (!WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, nchar, NULL, NULL)) {
- free(buf);
- buf = NULL;
- errno = EINVAL;
- }
- } else
- errno = EINVAL;
- } else
- errno = EINVAL;
- return buf;
-}
-
-char *
-_shttpd_getcwd(char *buffer, int maxlen)
-{
- char *result = NULL;
- wchar_t *wbuffer, *wresult;
-
- if (buffer) {
- /* User-supplied buffer */
- wbuffer = malloc(maxlen * sizeof(wchar_t));
- if (wbuffer == NULL)
- return NULL;
- } else
- /* Dynamically allocated buffer */
- wbuffer = NULL;
- wresult = _wgetcwd(wbuffer, maxlen);
- if (wresult) {
- int err = errno;
- if (buffer) {
- /* User-supplied buffer */
- int n = WideCharToMultiByte(CP_UTF8, 0, wresult, -1, buffer, maxlen, NULL, NULL);
- if (n == 0)
- err = ERANGE;
- free(wbuffer);
- result = buffer;
- } else {
- /* Buffer allocated by _wgetcwd() */
- result = wide_to_utf8(wresult);
- err = errno;
- free(wresult);
- }
- errno = err;
- }
- return result;
-}
-
-DIR *
-opendir(const char *name)
-{
- DIR *dir = NULL;
- char path[FILENAME_MAX];
- wchar_t wpath[FILENAME_MAX];
-
- if (name == NULL || name[0] == '\0') {
- errno = EINVAL;
- } else if ((dir = malloc(sizeof(*dir))) == NULL) {
- errno = ENOMEM;
- } else {
- _shttpd_snprintf(path, sizeof(path), "%s/*", name);
- fix_directory_separators(path);
- MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, sizeof(wpath));
- dir->handle = FindFirstFileW(wpath, &dir->info);
-
- if (dir->handle != INVALID_HANDLE_VALUE) {
- dir->result.d_name[0] = '\0';
- } else {
- free(dir);
- dir = NULL;
- }
- }
-
- return (dir);
-}
-
-int
-closedir(DIR *dir)
-{
- int result = -1;
-
- if (dir != NULL) {
- if (dir->handle != INVALID_HANDLE_VALUE)
- result = FindClose(dir->handle) ? 0 : -1;
-
- free(dir);
- }
-
- if (result == -1)
- errno = EBADF;
-
- return (result);
-}
-
-struct dirent *
-readdir(DIR *dir)
-{
- struct dirent *result = 0;
-
- if (dir && dir->handle != INVALID_HANDLE_VALUE) {
- if(!dir->result.d_name ||
- FindNextFileW(dir->handle, &dir->info)) {
- result = &dir->result;
-
- WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName,
- -1, result->d_name,
- sizeof(result->d_name), NULL, NULL);
- }
- } else {
- errno = EBADF;
- }
-
- return (result);
-}
-
-int
-_shttpd_set_non_blocking_mode(int fd)
-{
- unsigned long on = 1;
-
- return (ioctlsocket(fd, FIONBIO, &on));
-}
-
-void
-_shttpd_set_close_on_exec(int fd)
-{
- fd = 0; /* Do nothing. There is no FD_CLOEXEC on Windows */
-}
-
-#if !defined(NO_CGI)
-
-struct threadparam {
- SOCKET s;
- HANDLE hPipe;
- big_int_t content_len;
-};
-
-
-enum ready_mode_t {IS_READY_FOR_READ, IS_READY_FOR_WRITE};
-
-/*
- * Wait until given socket is in ready state. Always return TRUE.
- */
-static int
-is_socket_ready(int sock, enum ready_mode_t mode)
-{
- fd_set read_set, write_set;
-
- FD_ZERO(&read_set);
- FD_ZERO(&write_set);
-
- if (mode == IS_READY_FOR_READ)
- FD_SET(sock, &read_set);
- else
- FD_SET(sock, &write_set);
-
- select(sock + 1, &read_set, &write_set, NULL, NULL);
-
- return (TRUE);
-}
-
-/*
- * Thread function that reads POST data from the socket pair
- * and writes it to the CGI process.
- */
-static void//DWORD WINAPI
-stdoutput(void *arg)
-{
- struct threadparam *tp = arg;
- int n, sent, stop = 0;
- big_int_t total = 0;
- DWORD k;
- char buf[BUFSIZ];
- size_t max_recv;
-
- max_recv = min(sizeof(buf), tp->content_len - total);
- while (!stop &&
- max_recv > 0 &&
- is_socket_ready(tp->s, IS_READY_FOR_READ) &&
- (n = recv(tp->s, buf, max_recv, 0)) > 0) {
- if (n == -1 && ERRNO == EWOULDBLOCK)
- continue;
- for (sent = 0; !stop && sent < n; sent += k)
- if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0))
- stop++;
- total += n;
- max_recv = min(sizeof(buf), tp->content_len - total);
- }
-
- CloseHandle(tp->hPipe); /* Suppose we have POSTed everything */
- free(tp);
-}
-
-/*
- * Thread function that reads CGI output and pushes it to the socket pair.
- */
-static void
-stdinput(void *arg)
-{
- struct threadparam *tp = arg;
- static int ntotal;
- int k, stop = 0;
- DWORD n, sent;
- char buf[BUFSIZ];
-
- while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
- ntotal += n;
- for (sent = 0; !stop && sent < n; sent += k) {
- if (is_socket_ready(tp->s, IS_READY_FOR_WRITE) &&
- (k = send(tp->s, buf + sent, n - sent, 0)) <= 0) {
- if (k == -1 && ERRNO == EWOULDBLOCK) {
- k = 0;
- continue;
- }
- stop++;
- }
- }
- }
- CloseHandle(tp->hPipe);
-
- /*
- * Windows is a piece of crap. When this thread closes its end
- * of the socket pair, the other end (get_cgi() function) may loose
- * some data. I presume, this happens if get_cgi() is not fast enough,
- * and the data written by this end does not "push-ed" to the other
- * end socket buffer. So after closesocket() the remaining data is
- * gone. If I put shutdown() before closesocket(), that seems to
- * fix the problem, but I am not sure this is the right fix.
- * XXX (submitted by James Marshall) we do not do shutdown() on UNIX.
- * If fork() is called from user callback, shutdown() messes up things.
- */
- shutdown(tp->s, 2);
-
- closesocket(tp->s);
- free(tp);
-
- _endthread();
-}
-
-static void
-spawn_stdio_thread(int sock, HANDLE hPipe, void (*func)(void *),
- big_int_t content_len)
-{
- struct threadparam *tp;
- DWORD tid;
-
- tp = malloc(sizeof(*tp));
- assert(tp != NULL);
-
- tp->s = sock;
- tp->hPipe = hPipe;
- tp->content_len = content_len;
- _beginthread(func, 0, tp);
-}
-
-int
-_shttpd_spawn_process(struct conn *c, const char *prog, char *envblk,
- char *envp[], int sock, const char *dir)
-{
- HANDLE a[2], b[2], h[2], me;
- DWORD flags;
- char *p, *interp, cmdline[FILENAME_MAX], line[FILENAME_MAX];
- FILE *fp;
- STARTUPINFOA si;
- PROCESS_INFORMATION pi;
-
- me = GetCurrentProcess();
- flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
-
- /* FIXME add error checking code here */
- CreatePipe(&a[0], &a[1], NULL, 0);
- CreatePipe(&b[0], &b[1], NULL, 0);
- DuplicateHandle(me, a[0], me, &h[0], 0, TRUE, flags);
- DuplicateHandle(me, b[1], me, &h[1], 0, TRUE, flags);
-
- (void) memset(&si, 0, sizeof(si));
- (void) memset(&pi, 0, sizeof(pi));
-
- /* XXX redirect CGI errors to the error log file */
- si.cb = sizeof(si);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_HIDE;
- si.hStdOutput = h[1];
- si.hStdInput = h[0];
-
- /* If CGI file is a script, try to read the interpreter line */
- interp = c->ctx->options[OPT_CGI_INTERPRETER];
- if (interp == NULL) {
- if ((fp = fopen(prog, "r")) != NULL) {
- (void) fgets(line, sizeof(line), fp);
- if (memcmp(line, "#!", 2) != 0)
- line[2] = '\0';
- /* Trim whitespaces from interpreter name */
- for (p = &line[strlen(line) - 1]; p > line &&
- isspace(*p); p--)
- *p = '\0';
- (void) fclose(fp);
- }
- interp = line + 2;
- (void) _shttpd_snprintf(cmdline, sizeof(cmdline), "%s%s%s",
- line + 2, line[2] == '\0' ? "" : " ", prog);
- }
-
- if ((p = strrchr(prog, '/')) != NULL)
- prog = p + 1;
-
- (void) _shttpd_snprintf(cmdline, sizeof(cmdline), "%s %s", interp, prog);
-
- (void) _shttpd_snprintf(line, sizeof(line), "%s", dir);
- fix_directory_separators(line);
- fix_directory_separators(cmdline);
-
- /*
- * Spawn reader & writer threads before we create CGI process.
- * Otherwise CGI process may die too quickly, loosing the data
- */
- spawn_stdio_thread(sock, b[0], stdinput, 0);
- spawn_stdio_thread(sock, a[1], stdoutput, c->rem.content_len);
-
- if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
- CREATE_NEW_PROCESS_GROUP, envblk, line, &si, &pi) == 0) {
- _shttpd_elog(E_LOG, c,
- "redirect: CreateProcess(%s): %d", cmdline, ERRNO);
- return (-1);
- } else {
- CloseHandle(h[0]);
- CloseHandle(h[1]);
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
- }
-
- return (0);
-}
-
-#endif /* !NO_CGI */
-
-#define ID_TRAYICON 100
-#define ID_QUIT 101
-static NOTIFYICONDATA ni;
-
-static LRESULT CALLBACK
-WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- POINT pt;
- HMENU hMenu;
-
- switch (msg) {
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case ID_QUIT:
- exit(EXIT_SUCCESS);
- break;
- }
- break;
- case WM_USER:
- switch (lParam) {
- case WM_RBUTTONUP:
- case WM_LBUTTONUP:
- case WM_LBUTTONDBLCLK:
- hMenu = CreatePopupMenu();
- AppendMenu(hMenu, 0, ID_QUIT, "Exit SHTTPD");
- GetCursorPos(&pt);
- TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
- DestroyMenu(hMenu);
- break;
- }
- break;
- }
-
- return (DefWindowProc(hWnd, msg, wParam, lParam));
-}
-
-static void
-systray(void *arg)
-{
- WNDCLASS cls;
- HWND hWnd;
- MSG msg;
-
- (void) memset(&cls, 0, sizeof(cls));
-
- cls.lpfnWndProc = (WNDPROC) WindowProc;
- cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- cls.lpszClassName = "shttpd v." VERSION;
-
- if (!RegisterClass(&cls))
- _shttpd_elog(E_FATAL, NULL, "RegisterClass: %d", ERRNO);
- else if ((hWnd = CreateWindow(cls.lpszClassName, "",
- WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, arg)) == NULL)
- _shttpd_elog(E_FATAL, NULL, "CreateWindow: %d", ERRNO);
- ShowWindow(hWnd, SW_HIDE);
-
- ni.cbSize = sizeof(ni);
- ni.uID = ID_TRAYICON;
- ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
- ni.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- ni.hWnd = hWnd;
- _shttpd_snprintf(ni.szTip, sizeof(ni.szTip), "SHTTPD web server");
- ni.uCallbackMessage = WM_USER;
- Shell_NotifyIcon(NIM_ADD, &ni);
-
- while (GetMessage(&msg, hWnd, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-}
-
-int
-_shttpd_set_systray(struct shttpd_ctx *ctx, const char *opt)
-{
- HWND hWnd;
- char title[512];
- static WNDPROC oldproc;
-
- if (!_shttpd_is_true(opt))
- return (TRUE);
-
- FreeConsole();
- GetConsoleTitle(title, sizeof(title));
- hWnd = FindWindow(NULL, title);
- ShowWindow(hWnd, SW_HIDE);
- _beginthread(systray, 0, hWnd);
-
- return (TRUE);
-}
-
-int
-_shttpd_set_nt_service(struct shttpd_ctx *ctx, const char *action)
-{
- SC_HANDLE hSCM, hService;
- char path[FILENAME_MAX], key[128];
- HKEY hKey;
- DWORD dwData;
-
-
- if (!strcmp(action, "install")) {
- if ((hSCM = OpenSCManager(NULL, NULL,
- SC_MANAGER_ALL_ACCESS)) == NULL)
- _shttpd_elog(E_FATAL, NULL, "Error opening SCM (%d)", ERRNO);
-
- GetModuleFileName(NULL, path, sizeof(path));
-
- hService = CreateService(hSCM, SERVICE_NAME, SERVICE_NAME,
- SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
- SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path,
- NULL, NULL, NULL, NULL, NULL);
-
- if (!hService)
- _shttpd_elog(E_FATAL, NULL,
- "Error installing service (%d)", ERRNO);
-
- ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION,
- &service_descr);
- _shttpd_elog(E_FATAL, NULL, "Service successfully installed");
-
-
- } else if (!strcmp(action, "uninstall")) {
-
- if ((hSCM = OpenSCManager(NULL, NULL,
- SC_MANAGER_ALL_ACCESS)) == NULL) {
- _shttpd_elog(E_FATAL, NULL, "Error opening SCM (%d)", ERRNO);
- } else if ((hService = OpenService(hSCM,
- SERVICE_NAME, DELETE)) == NULL) {
- _shttpd_elog(E_FATAL, NULL,
- "Error opening service (%d)", ERRNO);
- } else if (!DeleteService(hService)) {
- _shttpd_elog(E_FATAL, NULL,
- "Error deleting service (%d)", ERRNO);
- } else {
- _shttpd_elog(E_FATAL, NULL, "Service deleted");
- }
-
- } else {
- _shttpd_elog(E_FATAL, NULL, "Use -service <install|uninstall>");
- }
-
- /* NOTREACHED */
- return (TRUE);
-}
-
-static void WINAPI
-ControlHandler(DWORD code)
-{
- if (code == SERVICE_CONTROL_STOP || code == SERVICE_CONTROL_SHUTDOWN) {
- ss.dwWin32ExitCode = 0;
- ss.dwCurrentState = SERVICE_STOPPED;
- }
-
- SetServiceStatus(hStatus, &ss);
-}
-
-static void WINAPI
-ServiceMain(int argc, char *argv[])
-{
- char path[MAX_PATH], *p, *av[] = {"shttpd_service", path, NULL};
- struct shttpd_ctx *ctx;
-
- ss.dwServiceType = SERVICE_WIN32;
- ss.dwCurrentState = SERVICE_RUNNING;
- ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
-
- hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, ControlHandler);
- SetServiceStatus(hStatus, &ss);
-
- GetModuleFileName(NULL, path, sizeof(path));
-
- if ((p = strrchr(path, DIRSEP)) != NULL)
- *++p = '\0';
-
- strcat(path, CONFIG_FILE); /* woo ! */
-
- ctx = shttpd_init(NELEMS(av) - 1, av);
- if ((ctx = shttpd_init(NELEMS(av) - 1, av)) == NULL)
- _shttpd_elog(E_FATAL, NULL, "Cannot initialize SHTTP context");
-
- while (ss.dwCurrentState == SERVICE_RUNNING)
- shttpd_poll(ctx, INT_MAX);
- shttpd_fini(ctx);
-
- ss.dwCurrentState = SERVICE_STOPPED;
- ss.dwWin32ExitCode = -1;
- SetServiceStatus(hStatus, &ss);
-}
-
-void
-try_to_run_as_nt_service(void)
-{
- static SERVICE_TABLE_ENTRY service_table[] = {
- {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
- {NULL, NULL}
- };
-
- if (StartServiceCtrlDispatcher(service_table))
- exit(EXIT_SUCCESS);
-}
diff --git a/vendor/shttpd/compat_win32.h b/vendor/shttpd/compat_win32.h
deleted file mode 100644
index 99ba99d..0000000
--- a/vendor/shttpd/compat_win32.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2004-2007 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-/* Tip from Justin Maximilian, suppress errors from winsock2.h */
-#define _WINSOCKAPI_
-
-#include <windows.h>
-#include <winsock2.h>
-#include <commctrl.h>
-#include <winnls.h>
-#include <shlobj.h>
-#include <shellapi.h>
-
-#ifndef _WIN32_WCE
-
-#include <process.h>
-#include <direct.h>
-#include <io.h>
-
-#else /* _WIN32_WCE */
-
-/* Windows CE-specific definitions */
-#define NO_CGI /* WinCE has no pipes */
-#define NO_GUI /* temporarily until it is fixed */
-#pragma comment(lib,"ws2")
-/* WinCE has both Unicode and ANSI versions of GetProcAddress */
-#undef GetProcAddress
-#define GetProcAddress GetProcAddressA
-#include "compat_wince.h"
-
-#endif /* _WIN32_WCE */
-
-#define ERRNO GetLastError()
-#define NO_SOCKLEN_T
-#define SSL_LIB L"ssleay32.dll"
-#define DIRSEP '\\'
-#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
-#define O_NONBLOCK 0
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
-#define mkdir(x,y) _mkdir(x)
-#define popen(x,y) _popen(x, y)
-#define pclose(x) _pclose(x)
-#define dlopen(x,y) LoadLibraryW(x)
-#define dlsym(x,y) (void *) GetProcAddress(x,y)
-#define _POSIX_
-
-#ifdef __LCC__
-#include <stdint.h>
-#endif /* __LCC__ */
-
-#ifdef _MSC_VER /* MinGW already has these */
-typedef unsigned int uint32_t;
-typedef unsigned short uint16_t;
-typedef __int64 uint64_t;
-#define S_ISDIR(x) ((x) & _S_IFDIR)
-#endif /* _MSC_VER */
-
-/*
- * POSIX dirent interface
- */
-struct dirent {
- char d_name[FILENAME_MAX];
-};
-
-typedef struct DIR {
- HANDLE handle;
- WIN32_FIND_DATAW info;
- struct dirent result;
- char *name;
-} DIR;
-
-extern DIR *opendir(const char *name);
-extern int closedir(DIR *dir);
-extern struct dirent *readdir(DIR *dir);
diff --git a/vendor/shttpd/compat_wince.c b/vendor/shttpd/compat_wince.c
deleted file mode 100644
index 36702f6..0000000
--- a/vendor/shttpd/compat_wince.c
+++ /dev/null
@@ -1,1593 +0,0 @@
-/*
- vi:ts=8:sw=8:noet
- * Copyright (c) 2006 Luke Dunstan <infidel(a)users.sourceforge.net>
- * Partly based on code by David Kashtan, Validus Medical Systems
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * This file provides various functions that are available on desktop Windows
- * but not on Windows CE
- */
-
-#ifdef _MSC_VER
-/* Level 4 warnings caused by windows.h */
-#pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
-#pragma warning(disable : 4115) // named type definition in parentheses
-#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
-#pragma warning(disable : 4514) // unreferenced inline function has been removed
-#pragma warning(disable : 4244) // conversion from 'int ' to 'unsigned short ', possible loss of data
-#pragma warning(disable : 4100) // unreferenced formal parameter
-#endif
-
-#include <windows.h>
-#include <stdlib.h>
-
-#include "compat_wince.h"
-
-
-static WCHAR *to_wide_string(LPCSTR pStr)
-{
- int nwide;
- WCHAR *buf;
-
- if(pStr == NULL)
- return NULL;
- nwide = MultiByteToWideChar(CP_ACP, 0, pStr, -1, NULL, 0);
- if(nwide == 0)
- return NULL;
- buf = malloc(nwide * sizeof(WCHAR));
- if(buf == NULL) {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return NULL;
- }
- if(MultiByteToWideChar(CP_ACP, 0, pStr, -1, buf, nwide) == 0) {
- free(buf);
- return NULL;
- }
- return buf;
-}
-
-FILE *fdopen(int handle, const char *mode)
-{
- WCHAR *wmode = to_wide_string(mode);
- FILE *result;
-
- if(wmode != NULL)
- result = _wfdopen((void *)handle, wmode);
- else
- result = NULL;
- free(wmode);
- return result;
-}
-
-/*
- * Time conversion constants
- */
-#define FT_EPOCH (116444736000000000i64)
-#define FT_TICKS (10000000i64)
-
- /*
- * Convert a FILETIME to a time_t
- */
-static time_t convert_FILETIME_to_time_t(FILETIME *File_Time)
-{
- __int64 Temp;
-
- /*
- * Convert the FILETIME structure to 100nSecs since 1601 (as a 64-bit value)
- */
- Temp = (((__int64)File_Time->dwHighDateTime) << 32) + (__int64)File_Time->dwLowDateTime;
- /*
- * Convert to seconds from 1970
- */
- return((time_t)((Temp - FT_EPOCH) / FT_TICKS));
-}
-
-/*
- * Convert a FILETIME to a tm structure
- */
-static struct tm *Convert_FILETIME_To_tm(FILETIME *File_Time)
-{
- SYSTEMTIME System_Time;
- static struct tm tm = {0};
- static const short Day_Of_Year_By_Month[12] = {(short)(0),
- (short)(31),
- (short)(31 + 28),
- (short)(31 + 28 + 31),
- (short)(31 + 28 + 31 + 30),
- (short)(31 + 28 + 31 + 30 + 31),
- (short)(31 + 28 + 31 + 30 + 31 + 30),
- (short)(31 + 28 + 31 + 30 + 31 + 30 + 31),
- (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31),
- (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30),
- (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31),
- (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30)};
-
-
- /*
- * Turn the FILETIME into a SYSTEMTIME
- */
- FileTimeToSystemTime(File_Time, &System_Time);
- /*
- * Use SYSTEMTIME to fill in the tm structure
- */
- tm.tm_sec = System_Time.wSecond;
- tm.tm_min = System_Time.wMinute;
- tm.tm_hour = System_Time.wHour;
- tm.tm_mday = System_Time.wDay;
- tm.tm_mon = System_Time.wMonth - 1;
- tm.tm_year = System_Time.wYear - 1900;
- tm.tm_wday = System_Time.wDayOfWeek;
- tm.tm_yday = Day_Of_Year_By_Month[tm.tm_mon] + tm.tm_mday - 1;
- if (tm.tm_mon >= 2) {
- /*
- * Check for leap year (every 4 years but not every 100 years but every 400 years)
- */
- if ((System_Time.wYear % 4) == 0) {
- /*
- * It Is a 4th year
- */
- if ((System_Time.wYear % 100) == 0) {
- /*
- * It is a 100th year
- */
- if ((System_Time.wYear % 400) == 0) {
- /*
- * It is a 400th year: It is a leap year
- */
- tm.tm_yday++;
- }
- } else {
- /*
- * It is not a 100th year: It is a leap year
- */
- tm.tm_yday++;
- }
- }
- }
- return(&tm);
-}
-
-/*
- * Convert a time_t to a FILETIME
- */
-static void Convert_time_t_To_FILETIME(time_t Time, FILETIME *File_Time)
-{
- __int64 Temp;
-
- /*
- * Use 64-bit calculation to convert seconds since 1970 to
- * 100nSecs since 1601
- */
- Temp = ((__int64)Time * FT_TICKS) + FT_EPOCH;
- /*
- * Put it into the FILETIME structure
- */
- File_Time->dwLowDateTime = (DWORD)Temp;
- File_Time->dwHighDateTime = (DWORD)(Temp >> 32);
-}
-
-/*
- * Convert a tm structure to a FILETIME
- */
-static FILETIME *Convert_tm_To_FILETIME(struct tm *tm)
-{
- SYSTEMTIME System_Time;
- static FILETIME File_Time = {0};
-
- /*
- * Use the tm structure to fill in a SYSTEM
- */
- System_Time.wYear = tm->tm_year + 1900;
- System_Time.wMonth = tm->tm_mon + 1;
- System_Time.wDayOfWeek = tm->tm_wday;
- System_Time.wDay = tm->tm_mday;
- System_Time.wHour = tm->tm_hour;
- System_Time.wMinute = tm->tm_min;
- System_Time.wSecond = tm->tm_sec;
- System_Time.wMilliseconds = 0;
- /*
- * Convert it to a FILETIME and return it
- */
- SystemTimeToFileTime(&System_Time, &File_Time);
- return(&File_Time);
-}
-
-
-/************************************************************************/
-/* */
-/* Errno emulation: There is no errno on Windows/CE and we need */
-/* to make it per-thread. So we have a function */
-/* that returns a pointer to the errno for the */
-/* current thread. */
-/* */
-/* If there is ONLY the main thread then we can */
-/* quickly return some static storage. */
-/* */
-/* If we have multiple threads running, we use */
-/* Thread-Local Storage to hold the pointer */
-/* */
-/************************************************************************/
-
-/*
- * Function pointer for returning errno pointer
- */
-static int *Initialize_Errno(void);
-int *(*__WinCE_Errno_Pointer_Function)(void) = Initialize_Errno;
-
-/*
- * Static errno storage for the main thread
- */
-static int Errno_Storage = 0;
-
-/*
- * Thread-Local storage slot for errno
- */
-static int TLS_Errno_Slot = 0xffffffff;
-
-/*
- * Number of threads we have running and critical section protection
- * for manipulating it
- */
-static int Number_Of_Threads = 0;
-static CRITICAL_SECTION Number_Of_Threads_Critical_Section;
-
-/*
- * For the main thread only -- return the errno pointer
- */
-static int *Get_Main_Thread_Errno(void)
-{
- return &Errno_Storage;
-}
-
-/*
- * When there is more than one thread -- return the errno pointer
- */
-static int *Get_Thread_Errno(void)
-{
- return (int *)TlsGetValue(TLS_Errno_Slot);
-}
-
-/*
- * Initialize a thread's errno
- */
-static void Initialize_Thread_Errno(int *Errno_Pointer)
-{
- /*
- * Make sure we have a slot
- */
- if (TLS_Errno_Slot == 0xffffffff) {
- /*
- * No: Get one
- */
- TLS_Errno_Slot = (int)TlsAlloc();
- if (TLS_Errno_Slot == 0xffffffff) ExitProcess(3);
- }
- /*
- * We can safely check for 0 threads, because
- * only the main thread will be initializing
- * at this point. Make sure the critical
- * section that protects the number of threads
- * is initialized
- */
- if (Number_Of_Threads == 0)
- InitializeCriticalSection(&Number_Of_Threads_Critical_Section);
- /*
- * Store the errno pointer
- */
- if (TlsSetValue(TLS_Errno_Slot, (LPVOID)Errno_Pointer) == 0) ExitProcess(3);
- /*
- * Bump the number of threads
- */
- EnterCriticalSection(&Number_Of_Threads_Critical_Section);
- Number_Of_Threads++;
- if (Number_Of_Threads > 1) {
- /*
- * We have threads other than the main thread:
- * Use thread-local storage
- */
- __WinCE_Errno_Pointer_Function = Get_Thread_Errno;
- }
- LeaveCriticalSection(&Number_Of_Threads_Critical_Section);
-}
-
-/*
- * Initialize errno emulation on Windows/CE (Main thread)
- */
-static int *Initialize_Errno(void)
-{
- /*
- * Initialize the main thread's errno in thread-local storage
- */
- Initialize_Thread_Errno(&Errno_Storage);
- /*
- * Set the errno function to be the one that returns the
- * main thread's errno
- */
- __WinCE_Errno_Pointer_Function = Get_Main_Thread_Errno;
- /*
- * Return the main thread's errno
- */
- return &Errno_Storage;
-}
-
-/*
- * Initialize errno emulation on Windows/CE (New thread)
- */
-void __WinCE_Errno_New_Thread(int *Errno_Pointer)
-{
- Initialize_Thread_Errno(Errno_Pointer);
-}
-
-/*
- * Note that a thread has exited
- */
-void __WinCE_Errno_Thread_Exit(void)
-{
- /*
- * Decrease the number of threads
- */
- EnterCriticalSection(&Number_Of_Threads_Critical_Section);
- Number_Of_Threads--;
- if (Number_Of_Threads <= 1) {
- /*
- * We only have the main thread
- */
- __WinCE_Errno_Pointer_Function = Get_Main_Thread_Errno;
- }
- LeaveCriticalSection(&Number_Of_Threads_Critical_Section);
-}
-
-
-char *
-strerror(int errnum)
-{
- return "(strerror not implemented)";
-}
-
-#define FT_EPOCH (116444736000000000i64)
-#define FT_TICKS (10000000i64)
-
-int
-_wstat(const WCHAR *path, struct _stat *buffer)
-{
- WIN32_FIND_DATA data;
- HANDLE handle;
- WCHAR *p;
-
- /* Fail if wildcard characters are specified */
- if (wcscspn(path, L"?*") != wcslen(path))
- return -1;
-
- handle = FindFirstFile(path, &data);
- if (handle == INVALID_HANDLE_VALUE) {
- errno = GetLastError();
- return -1;
- }
- FindClose(handle);
-
- /* Found: Convert the file times */
- buffer->st_mtime = convert_FILETIME_to_time_t(&data.ftLastWriteTime);
- if (data.ftLastAccessTime.dwLowDateTime || data.ftLastAccessTime.dwHighDateTime)
- buffer->st_atime = convert_FILETIME_to_time_t(&data.ftLastAccessTime);
- else
- buffer->st_atime = buffer->st_mtime;
- if (data.ftCreationTime.dwLowDateTime || data.ftCreationTime.dwHighDateTime)
- buffer->st_ctime = convert_FILETIME_to_time_t(&data.ftCreationTime);
- else
- buffer->st_ctime = buffer->st_mtime;
-
- /* Convert the file modes */
- buffer->st_mode = (unsigned short)((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR | S_IEXEC) : S_IFREG);
- buffer->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : (S_IREAD | S_IWRITE);
- if((p = wcsrchr(path, L'.')) != NULL) {
- p++;
- if (_wcsicmp(p, L".exe") == 0)
- buffer->st_mode |= S_IEXEC;
- }
- buffer->st_mode |= (buffer->st_mode & 0700) >> 3;
- buffer->st_mode |= (buffer->st_mode & 0700) >> 6;
- /* Set the other information */
- buffer->st_nlink = 1;
- buffer->st_size = (unsigned long int)data.nFileSizeLow;
- buffer->st_uid = 0;
- buffer->st_gid = 0;
- buffer->st_ino = 0 /*data.dwOID ?*/;
- buffer->st_dev = 0;
-
- return 0; /* success */
-}
-
-/*
- * Helper function for cemodule -- do an fstat() operation on a Win32 File Handle
- */
-int
-_fstat(int handle, struct _stat *st)
-{
- BY_HANDLE_FILE_INFORMATION Data;
-
- /*
- * Get the file information
- */
- if (!GetFileInformationByHandle((HANDLE)handle, &Data)) {
- /*
- * Return error
- */
- errno = GetLastError();
- return(-1);
- }
- /*
- * Found: Convert the file times
- */
- st->st_mtime=(time_t)((*(__int64*)&Data.ftLastWriteTime-FT_EPOCH)/FT_TICKS);
- if(Data.ftLastAccessTime.dwLowDateTime || Data.ftLastAccessTime.dwHighDateTime)
- st->st_atime=(time_t)((*(__int64*)&Data.ftLastAccessTime-FT_EPOCH)/FT_TICKS);
- else
- st->st_atime=st->st_mtime ;
- if(Data.ftCreationTime.dwLowDateTime || Data.ftCreationTime.dwHighDateTime )
- st->st_ctime=(time_t)((*(__int64*)&Data.ftCreationTime-FT_EPOCH)/FT_TICKS);
- else
- st->st_ctime=st->st_mtime ;
- /*
- * Convert the file modes
- */
- st->st_mode = (unsigned short)((Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR | S_IEXEC) : S_IFREG);
- st->st_mode |= (Data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : (S_IREAD | S_IWRITE);
- st->st_mode |= (st->st_mode & 0700) >> 3;
- st->st_mode |= (st->st_mode & 0700) >> 6;
- /*
- * Set the other information
- */
- st->st_nlink=1;
- st->st_size=(unsigned long int)Data.nFileSizeLow;
- st->st_uid=0;
- st->st_gid=0;
- st->st_ino=0;
- st->st_dev=0;
- /*
- * Return success
- */
- return(0);
-}
-
-int _wopen(const wchar_t *filename, int oflag, ...)
-{
- DWORD Access, ShareMode, CreationDisposition;
- HANDLE Handle;
- static int Modes[4] = {0, (GENERIC_READ | GENERIC_WRITE), GENERIC_READ, GENERIC_WRITE};
-
- /*
- * Calculate the CreateFile arguments
- */
- Access = Modes[oflag & O_MODE_MASK];
- ShareMode = (oflag & O_EXCL) ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE);
- if (oflag & O_TRUNC)
- CreationDisposition = (oflag & O_CREAT) ? CREATE_ALWAYS : TRUNCATE_EXISTING;
- else
- CreationDisposition = (oflag & O_CREAT) ? CREATE_NEW : OPEN_EXISTING;
-
- Handle = CreateFileW(filename, Access, ShareMode, NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
-
- /*
- * Deal with errors
- */
- if (Handle == INVALID_HANDLE_VALUE) {
- errno = GetLastError();
- if ((errno == ERROR_ALREADY_EXISTS) || (errno == ERROR_FILE_EXISTS))
- errno = ERROR_ALREADY_EXISTS;
- return -1;
- }
- /*
- * Return the handle
- */
- return (int)Handle;
-}
-
-int
-_close(int handle)
-{
- if(CloseHandle((HANDLE)handle))
- return 0;
- errno = GetLastError();
- return -1;
-}
-
-int
-_write(int handle, const void *buffer, unsigned int count)
-{
- DWORD numwritten = 0;
- if(!WriteFile((HANDLE)handle, buffer, count, &numwritten, NULL)) {
- errno = GetLastError();
- return -1;
- }
- return numwritten;
-}
-
-int
-_read(int handle, void *buffer, unsigned int count)
-{
- DWORD numread = 0;
- if(!ReadFile((HANDLE)handle, buffer, count, &numread, NULL)) {
- errno = GetLastError();
- return -1;
- }
- return numread;
-}
-
-long
-_lseek(int handle, long offset, int origin)
-{
- DWORD dwMoveMethod;
- DWORD result;
-
- switch(origin) {
- default:
- errno = EINVAL;
- return -1L;
- case SEEK_SET:
- dwMoveMethod = FILE_BEGIN;
- break;
- case SEEK_CUR:
- dwMoveMethod = FILE_CURRENT;
- break;
- case SEEK_END:
- dwMoveMethod = FILE_END;
- break;
- }
- result = SetFilePointer((HANDLE)handle, offset, NULL, dwMoveMethod);
- if(result == 0xFFFFFFFF) {
- errno = GetLastError();
- return -1;
- }
- return (long)result;
-}
-
-int
-_wmkdir(const wchar_t *dirname)
-{
- if(!CreateDirectoryW(dirname, NULL)) {
- errno = GetLastError();
- return -1;
- }
- return 0;
-}
-
-int
-_wremove(const wchar_t *filename)
-{
- if(!DeleteFileW(filename)) {
- errno = GetLastError();
- return -1;
- }
- return 0;
-}
-
-int
-_wrename(const wchar_t *oldname, const wchar_t *newname)
-{
- if(!MoveFileW(oldname, newname)) {
- errno = GetLastError();
- return -1;
- }
- return 0;
-}
-
-wchar_t *
-_wgetcwd(wchar_t *buffer, int maxlen)
-{
- wchar_t *result;
- WCHAR wszPath[MAX_PATH + 1];
- WCHAR *p;
-
- if(!GetModuleFileNameW(NULL, wszPath, MAX_PATH + 1)) {
- errno = GetLastError();
- return NULL;
- }
- /* Remove the filename part of the path to leave the directory */
- p = wcsrchr(wszPath, L'\\');
- if(p)
- *p = L'\0';
-
- if(buffer == NULL)
- result = _wcsdup(wszPath);
- else if(wcslen(wszPath) + 1 > (size_t)maxlen) {
- result = NULL;
- errno = ERROR_INSUFFICIENT_BUFFER;
- } else {
- wcsncpy(buffer, wszPath, maxlen);
- buffer[maxlen - 1] = L'\0';
- result = buffer;
- }
- return result;
-}
-
-/*
- * The missing "C" runtime gmtime() function
- */
-struct tm *gmtime(const time_t *TimeP)
-{
- FILETIME File_Time;
-
- /*
- * Deal with null time pointer
- */
- if (!TimeP) return(NULL);
- /*
- * time_t -> FILETIME -> tm
- */
- Convert_time_t_To_FILETIME(*TimeP, &File_Time);
- return(Convert_FILETIME_To_tm(&File_Time));
-}
-
-/*
- * The missing "C" runtime localtime() function
- */
-struct tm *localtime(const time_t *TimeP)
-{
- FILETIME File_Time, Local_File_Time;
-
- /*
- * Deal with null time pointer
- */
- if (!TimeP) return(NULL);
- /*
- * time_t -> FILETIME -> Local FILETIME -> tm
- */
- Convert_time_t_To_FILETIME(*TimeP, &File_Time);
- FileTimeToLocalFileTime(&File_Time, &Local_File_Time);
- return(Convert_FILETIME_To_tm(&Local_File_Time));
-}
-
-/*
- * The missing "C" runtime mktime() function
- */
-time_t mktime(struct tm *tm)
-{
- FILETIME *Local_File_Time;
- FILETIME File_Time;
-
- /*
- * tm -> Local FILETIME -> FILETIME -> time_t
- */
- Local_File_Time = Convert_tm_To_FILETIME(tm);
- LocalFileTimeToFileTime(Local_File_Time, &File_Time);
- return(convert_FILETIME_to_time_t(&File_Time));
-}
-
-/*
- * Missing "C" runtime time() function
- */
-time_t time(time_t *TimeP)
-{
- SYSTEMTIME System_Time;
- FILETIME File_Time;
- time_t Result;
-
- /*
- * Get the current system time
- */
- GetSystemTime(&System_Time);
- /*
- * SYSTEMTIME -> FILETIME -> time_t
- */
- SystemTimeToFileTime(&System_Time, &File_Time);
- Result = convert_FILETIME_to_time_t(&File_Time);
- /*
- * Return the time_t
- */
- if (TimeP) *TimeP = Result;
- return(Result);
-}
-
-static char Standard_Name[32] = "GMT";
-static char Daylight_Name[32] = "GMT";
-char *tzname[2] = {Standard_Name, Daylight_Name};
-long timezone = 0;
-int daylight = 0;
-
-void tzset(void)
-{
- TIME_ZONE_INFORMATION Info;
- int Result;
-
- /*
- * Get our current timezone information
- */
- Result = GetTimeZoneInformation(&Info);
- switch(Result) {
- /*
- * We are on standard time
- */
- case TIME_ZONE_ID_STANDARD:
- daylight = 0;
- break;
- /*
- * We are on daylight savings time
- */
- case TIME_ZONE_ID_DAYLIGHT:
- daylight = 1;
- break;
- /*
- * We don't know the timezone information (leave it GMT)
- */
- default: return;
- }
- /*
- * Extract the timezone information
- */
- timezone = Info.Bias * 60;
- if (Info.StandardName[0])
- WideCharToMultiByte(CP_ACP, 0, Info.StandardName, -1, Standard_Name, sizeof(Standard_Name) - 1, NULL, NULL);
- if (Info.DaylightName[0])
- WideCharToMultiByte(CP_ACP, 0, Info.DaylightName, -1, Daylight_Name, sizeof(Daylight_Name) - 1, NULL, NULL);
-}
-
-/*** strftime() from newlib libc/time/strftime.c ***/
-
-/*
- * Sane snprintf(). Acts like snprintf(), but never return -1 or the
- * value bigger than supplied buffer.
- */
-static int
-Snprintf(char *buf, size_t buflen, const char *fmt, ...)
-{
- va_list ap;
- int n;
-
- if (buflen == 0)
- return (0);
-
- va_start(ap, fmt);
- n = _vsnprintf(buf, buflen, fmt, ap);
- va_end(ap);
-
- if (n < 0 || n > (int) buflen - 1) {
- n = buflen - 1;
- }
- buf[n] = '\0';
-
- return (n);
-}
-
-#define snprintf Snprintf
-
-/* from libc/include/_ansi.h */
-#define _CONST const
-#define _DEFUN(name, arglist, args) name(args)
-#define _AND ,
-/* from libc/time/local.h */
-#define TZ_LOCK
-#define TZ_UNLOCK
-#define _tzname tzname
-#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
-#define YEAR_BASE 1900
-#define SECSPERMIN 60L
-#define MINSPERHOUR 60L
-#define HOURSPERDAY 24L
-#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
-
-/*
- * strftime.c
- * Original Author: G. Haley
- * Additions from: Eric Blake
- *
- * Places characters into the array pointed to by s as controlled by the string
- * pointed to by format. If the total number of resulting characters including
- * the terminating null character is not more than maxsize, returns the number
- * of characters placed into the array pointed to by s (not including the
- * terminating null character); otherwise zero is returned and the contents of
- * the array indeterminate.
- */
-
-/*
-FUNCTION
-<<strftime>>---flexible calendar time formatter
-
-INDEX
- strftime
-
-ANSI_SYNOPSIS
- #include <time.h>
- size_t strftime(char *<[s]>, size_t <[maxsize]>,
- const char *<[format]>, const struct tm *<[timp]>);
-
-TRAD_SYNOPSIS
- #include <time.h>
- size_t strftime(<[s]>, <[maxsize]>, <[format]>, <[timp]>)
- char *<[s]>;
- size_t <[maxsize]>;
- char *<[format]>;
- struct tm *<[timp]>;
-
-DESCRIPTION
-<<strftime>> converts a <<struct tm>> representation of the time (at
-<[timp]>) into a null-terminated string, starting at <[s]> and occupying
-no more than <[maxsize]> characters.
-
-You control the format of the output using the string at <[format]>.
-<<*<[format]>>> can contain two kinds of specifications: text to be
-copied literally into the formatted string, and time conversion
-specifications. Time conversion specifications are two- and
-three-character sequences beginning with `<<%>>' (use `<<%%>>' to
-include a percent sign in the output). Each defined conversion
-specification selects only the specified field(s) of calendar time
-data from <<*<[timp]>>>, and converts it to a string in one of the
-following ways:
-
-o+
-o %a
-A three-letter abbreviation for the day of the week. [tm_wday]
-
-o %A
-The full name for the day of the week, one of `<<Sunday>>',
-`<<Monday>>', `<<Tuesday>>', `<<Wednesday>>', `<<Thursday>>',
-`<<Friday>>', or `<<Saturday>>'. [tm_wday]
-
-o %b
-A three-letter abbreviation for the month name. [tm_mon]
-
-o %B
-The full name of the month, one of `<<January>>', `<<February>>',
-`<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>',
-`<<August>>', `<<September>>', `<<October>>', `<<November>>',
-`<<December>>'. [tm_mon]
-
-o %c
-A string representing the complete date and time, in the form
-`<<"%a %b %e %H:%M:%S %Y">>' (example "Mon Apr 01 13:13:13
-1992"). [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
-
-o %C
-The century, that is, the year divided by 100 then truncated. For
-4-digit years, the result is zero-padded and exactly two characters;
-but for other years, there may a negative sign or more digits. In
-this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year]
-
-o %d
-The day of the month, formatted with two digits (from `<<01>>' to
-`<<31>>'). [tm_mday]
-
-o %D
-A string representing the date, in the form `<<"%m/%d/%y">>'.
-[tm_mday, tm_mon, tm_year]
-
-o %e
-The day of the month, formatted with leading space if single digit
-(from `<<1>>' to `<<31>>'). [tm_mday]
-
-o %E<<x>>
-In some locales, the E modifier selects alternative representations of
-certain modifiers <<x>>. But in the "C" locale supported by newlib,
-it is ignored, and treated as %<<x>>.
-
-o %F
-A string representing the ISO 8601:2000 date format, in the form
-`<<"%Y-%m-%d">>'. [tm_mday, tm_mon, tm_year]
-
-o %g
-The last two digits of the week-based year, see specifier %G (from
-`<<00>>' to `<<99>>'). [tm_year, tm_wday, tm_yday]
-
-o %G
-The week-based year. In the ISO 8601:2000 calendar, week 1 of the year
-includes January 4th, and begin on Mondays. Therefore, if January 1st,
-2nd, or 3rd falls on a Sunday, that day and earlier belong to the last
-week of the previous year; and if December 29th, 30th, or 31st falls
-on Monday, that day and later belong to week 1 of the next year. For
-consistency with %Y, it always has at least four characters.
-Example: "%G" for Saturday 2nd January 1999 gives "1998", and for
-Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday]
-
-o %h
-A three-letter abbreviation for the month name (synonym for
-"%b"). [tm_mon]
-
-o %H
-The hour (on a 24-hour clock), formatted with two digits (from
-`<<00>>' to `<<23>>'). [tm_hour]
-
-o %I
-The hour (on a 12-hour clock), formatted with two digits (from
-`<<01>>' to `<<12>>'). [tm_hour]
-
-o %j
-The count of days in the year, formatted with three digits
-(from `<<001>>' to `<<366>>'). [tm_yday]
-
-o %k
-The hour (on a 24-hour clock), formatted with leading space if single
-digit (from `<<0>>' to `<<23>>'). Non-POSIX extension. [tm_hour]
-
-o %l
-The hour (on a 12-hour clock), formatted with leading space if single
-digit (from `<<1>>' to `<<12>>'). Non-POSIX extension. [tm_hour]
-
-o %m
-The month number, formatted with two digits (from `<<01>>' to `<<12>>').
-[tm_mon]
-
-o %M
-The minute, formatted with two digits (from `<<00>>' to `<<59>>'). [tm_min]
-
-o %n
-A newline character (`<<\n>>').
-
-o %O<<x>>
-In some locales, the O modifier selects alternative digit characters
-for certain modifiers <<x>>. But in the "C" locale supported by newlib, it
-is ignored, and treated as %<<x>>.
-
-o %p
-Either `<<AM>>' or `<<PM>>' as appropriate. [tm_hour]
-
-o %r
-The 12-hour time, to the second. Equivalent to "%I:%M:%S %p". [tm_sec,
-tm_min, tm_hour]
-
-o %R
-The 24-hour time, to the minute. Equivalent to "%H:%M". [tm_min, tm_hour]
-
-o %S
-The second, formatted with two digits (from `<<00>>' to `<<60>>'). The
-value 60 accounts for the occasional leap second. [tm_sec]
-
-o %t
-A tab character (`<<\t>>').
-
-o %T
-The 24-hour time, to the second. Equivalent to "%H:%M:%S". [tm_sec,
-tm_min, tm_hour]
-
-o %u
-The weekday as a number, 1-based from Monday (from `<<1>>' to
-`<<7>>'). [tm_wday]
-
-o %U
-The week number, where weeks start on Sunday, week 1 contains the first
-Sunday in a year, and earlier days are in week 0. Formatted with two
-digits (from `<<00>>' to `<<53>>'). See also <<%W>>. [tm_wday, tm_yday]
-
-o %V
-The week number, where weeks start on Monday, week 1 contains January 4th,
-and earlier days are in the previous year. Formatted with two digits
-(from `<<01>>' to `<<53>>'). See also <<%G>>. [tm_year, tm_wday, tm_yday]
-
-o %w
-The weekday as a number, 0-based from Sunday (from `<<0>>' to `<<6>>').
-[tm_wday]
-
-o %W
-The week number, where weeks start on Monday, week 1 contains the first
-Monday in a year, and earlier days are in week 0. Formatted with two
-digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday]
-
-o %x
-A string representing the complete date, equivalent to "%m/%d/%y".
-[tm_mon, tm_mday, tm_year]
-
-o %X
-A string representing the full time of day (hours, minutes, and
-seconds), equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
-
-o %y
-The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year]
-
-o %Y
-The full year, equivalent to <<%C%y>>. It will always have at least four
-characters, but may have more. The year is accurate even when tm_year
-added to the offset of 1900 overflows an int. [tm_year]
-
-o %z
-The offset from UTC. The format consists of a sign (negative is west of
-Greewich), two characters for hour, then two characters for minutes
-(-hhmm or +hhmm). If tm_isdst is negative, the offset is unknown and no
-output is generated; if it is zero, the offset is the standard offset for
-the current time zone; and if it is positive, the offset is the daylight
-savings offset for the current timezone. The offset is determined from
-the TZ environment variable, as if by calling tzset(). [tm_isdst]
-
-o %Z
-The time zone name. If tm_isdst is negative, no output is generated.
-Otherwise, the time zone name is based on the TZ environment variable,
-as if by calling tzset(). [tm_isdst]
-
-o %%
-A single character, `<<%>>'.
-o-
-
-RETURNS
-When the formatted time takes up no more than <[maxsize]> characters,
-the result is the length of the formatted string. Otherwise, if the
-formatting operation was abandoned due to lack of room, the result is
-<<0>>, and the string starting at <[s]> corresponds to just those
-parts of <<*<[format]>>> that could be completely filled in within the
-<[maxsize]> limit.
-
-PORTABILITY
-ANSI C requires <<strftime>>, but does not specify the contents of
-<<*<[s]>>> when the formatted string would require more than
-<[maxsize]> characters. Unrecognized specifiers and fields of
-<<timp>> that are out of range cause undefined results. Since some
-formats expand to 0 bytes, it is wise to set <<*<[s]>>> to a nonzero
-value beforehand to distinguish between failure and an empty string.
-This implementation does not support <<s>> being NULL, nor overlapping
-<<s>> and <<format>>.
-
-<<strftime>> requires no supporting OS subroutines.
-*/
-
-static _CONST int dname_len[7] =
-{6, 6, 7, 9, 8, 6, 8};
-
-static _CONST char *_CONST dname[7] =
-{"Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday"};
-
-static _CONST int mname_len[12] =
-{7, 8, 5, 5, 3, 4, 4, 6, 9, 7, 8, 8};
-
-static _CONST char *_CONST mname[12] =
-{"January", "February", "March", "April",
- "May", "June", "July", "August", "September", "October", "November",
- "December"};
-
-/* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return
- -1, 0, or 1 as the adjustment to add to the year for the ISO week
- numbering used in "%g%G%V", avoiding overflow. */
-static int
-_DEFUN (iso_year_adjust, (tim_p),
- _CONST struct tm *tim_p)
-{
- /* Account for fact that tm_year==0 is year 1900. */
- int leap = isleap (tim_p->tm_year + (YEAR_BASE
- - (tim_p->tm_year < 0 ? 0 : 2000)));
-
- /* Pack the yday, wday, and leap year into a single int since there are so
- many disparate cases. */
-#define PACK(yd, wd, lp) (((yd) << 4) + (wd << 1) + (lp))
- switch (PACK (tim_p->tm_yday, tim_p->tm_wday, leap))
- {
- case PACK (0, 5, 0): /* Jan 1 is Fri, not leap. */
- case PACK (0, 6, 0): /* Jan 1 is Sat, not leap. */
- case PACK (0, 0, 0): /* Jan 1 is Sun, not leap. */
- case PACK (0, 5, 1): /* Jan 1 is Fri, leap year. */
- case PACK (0, 6, 1): /* Jan 1 is Sat, leap year. */
- case PACK (0, 0, 1): /* Jan 1 is Sun, leap year. */
- case PACK (1, 6, 0): /* Jan 2 is Sat, not leap. */
- case PACK (1, 0, 0): /* Jan 2 is Sun, not leap. */
- case PACK (1, 6, 1): /* Jan 2 is Sat, leap year. */
- case PACK (1, 0, 1): /* Jan 2 is Sun, leap year. */
- case PACK (2, 0, 0): /* Jan 3 is Sun, not leap. */
- case PACK (2, 0, 1): /* Jan 3 is Sun, leap year. */
- return -1; /* Belongs to last week of previous year. */
- case PACK (362, 1, 0): /* Dec 29 is Mon, not leap. */
- case PACK (363, 1, 1): /* Dec 29 is Mon, leap year. */
- case PACK (363, 1, 0): /* Dec 30 is Mon, not leap. */
- case PACK (363, 2, 0): /* Dec 30 is Tue, not leap. */
- case PACK (364, 1, 1): /* Dec 30 is Mon, leap year. */
- case PACK (364, 2, 1): /* Dec 30 is Tue, leap year. */
- case PACK (364, 1, 0): /* Dec 31 is Mon, not leap. */
- case PACK (364, 2, 0): /* Dec 31 is Tue, not leap. */
- case PACK (364, 3, 0): /* Dec 31 is Wed, not leap. */
- case PACK (365, 1, 1): /* Dec 31 is Mon, leap year. */
- case PACK (365, 2, 1): /* Dec 31 is Tue, leap year. */
- case PACK (365, 3, 1): /* Dec 31 is Wed, leap year. */
- return 1; /* Belongs to first week of next year. */
- }
- return 0; /* Belongs to specified year. */
-#undef PACK
-}
-
-size_t
-_DEFUN (strftime, (s, maxsize, format, tim_p),
- char *s _AND
- size_t maxsize _AND
- _CONST char *format _AND
- _CONST struct tm *tim_p)
-{
- size_t count = 0;
- int i;
-
- for (;;)
- {
- while (*format && *format != '%')
- {
- if (count < maxsize - 1)
- s[count++] = *format++;
- else
- return 0;
- }
-
- if (*format == '\0')
- break;
-
- format++;
- if (*format == 'E' || *format == 'O')
- format++;
-
- switch (*format)
- {
- case 'a':
- for (i = 0; i < 3; i++)
- {
- if (count < maxsize - 1)
- s[count++] =
- dname[tim_p->tm_wday][i];
- else
- return 0;
- }
- break;
- case 'A':
- for (i = 0; i < dname_len[tim_p->tm_wday]; i++)
- {
- if (count < maxsize - 1)
- s[count++] =
- dname[tim_p->tm_wday][i];
- else
- return 0;
- }
- break;
- case 'b':
- case 'h':
- for (i = 0; i < 3; i++)
- {
- if (count < maxsize - 1)
- s[count++] =
- mname[tim_p->tm_mon][i];
- else
- return 0;
- }
- break;
- case 'B':
- for (i = 0; i < mname_len[tim_p->tm_mon]; i++)
- {
- if (count < maxsize - 1)
- s[count++] =
- mname[tim_p->tm_mon][i];
- else
- return 0;
- }
- break;
- case 'c':
- {
- /* Length is not known because of %C%y, so recurse. */
- size_t adjust = strftime (&s[count], maxsize - count,
- "%a %b %e %H:%M:%S %C%y", tim_p);
- if (adjust > 0)
- count += adjust;
- else
- return 0;
- }
- break;
- case 'C':
- {
- /* Examples of (tm_year + YEAR_BASE) that show how %Y == %C%y
- with 32-bit int.
- %Y %C %y
- 2147485547 21474855 47
- 10000 100 00
- 9999 99 99
- 0999 09 99
- 0099 00 99
- 0001 00 01
- 0000 00 00
- -001 -0 01
- -099 -0 99
- -999 -9 99
- -1000 -10 00
- -10000 -100 00
- -2147481748 -21474817 48
-
- Be careful of both overflow and sign adjustment due to the
- asymmetric range of years.
- */
- int neg = tim_p->tm_year < -YEAR_BASE;
- int century = tim_p->tm_year >= 0
- ? tim_p->tm_year / 100 + YEAR_BASE / 100
- : abs (tim_p->tm_year + YEAR_BASE) / 100;
- count += snprintf (&s[count], maxsize - count, "%s%.*d",
- neg ? "-" : "", 2 - neg, century);
- if (count >= maxsize)
- return 0;
- }
- break;
- case 'd':
- case 'e':
- if (count < maxsize - 2)
- {
- sprintf (&s[count], *format == 'd' ? "%.2d" : "%2d",
- tim_p->tm_mday);
- count += 2;
- }
- else
- return 0;
- break;
- case 'D':
- case 'x':
- /* %m/%d/%y */
- if (count < maxsize - 8)
- {
- sprintf (&s[count], "%.2d/%.2d/%.2d",
- tim_p->tm_mon + 1, tim_p->tm_mday,
- tim_p->tm_year >= 0 ? tim_p->tm_year % 100
- : abs (tim_p->tm_year + YEAR_BASE) % 100);
- count += 8;
- }
- else
- return 0;
- break;
- case 'F':
- {
- /* Length is not known because of %C%y, so recurse. */
- size_t adjust = strftime (&s[count], maxsize - count,
- "%C%y-%m-%d", tim_p);
- if (adjust > 0)
- count += adjust;
- else
- return 0;
- }
- break;
- case 'g':
- if (count < maxsize - 2)
- {
- /* Be careful of both overflow and negative years, thanks to
- the asymmetric range of years. */
- int adjust = iso_year_adjust (tim_p);
- int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
- : abs (tim_p->tm_year + YEAR_BASE) % 100;
- if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
- adjust = 1;
- else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
- adjust = -1;
- sprintf (&s[count], "%.2d",
- ((year + adjust) % 100 + 100) % 100);
- count += 2;
- }
- else
- return 0;
- break;
- case 'G':
- {
- /* See the comments for 'C' and 'Y'; this is a variable length
- field. Although there is no requirement for a minimum number
- of digits, we use 4 for consistency with 'Y'. */
- int neg = tim_p->tm_year < -YEAR_BASE;
- int adjust = iso_year_adjust (tim_p);
- int century = tim_p->tm_year >= 0
- ? tim_p->tm_year / 100 + YEAR_BASE / 100
- : abs (tim_p->tm_year + YEAR_BASE) / 100;
- int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
- : abs (tim_p->tm_year + YEAR_BASE) % 100;
- if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
- neg = adjust = 1;
- else if (adjust > 0 && neg)
- adjust = -1;
- year += adjust;
- if (year == -1)
- {
- year = 99;
- --century;
- }
- else if (year == 100)
- {
- year = 0;
- ++century;
- }
- count += snprintf (&s[count], maxsize - count, "%s%.*d%.2d",
- neg ? "-" : "", 2 - neg, century, year);
- if (count >= maxsize)
- return 0;
- }
- break;
- case 'H':
- case 'k':
- if (count < maxsize - 2)
- {
- sprintf (&s[count], *format == 'k' ? "%2d" : "%.2d",
- tim_p->tm_hour);
- count += 2;
- }
- else
- return 0;
- break;
- case 'I':
- case 'l':
- if (count < maxsize - 2)
- {
- if (tim_p->tm_hour == 0 ||
- tim_p->tm_hour == 12)
- {
- s[count++] = '1';
- s[count++] = '2';
- }
- else
- {
- sprintf (&s[count], *format == 'I' ? "%.2d" : "%2d",
- tim_p->tm_hour % 12);
- count += 2;
- }
- }
- else
- return 0;
- break;
- case 'j':
- if (count < maxsize - 3)
- {
- sprintf (&s[count], "%.3d",
- tim_p->tm_yday + 1);
- count += 3;
- }
- else
- return 0;
- break;
- case 'm':
- if (count < maxsize - 2)
- {
- sprintf (&s[count], "%.2d",
- tim_p->tm_mon + 1);
- count += 2;
- }
- else
- return 0;
- break;
- case 'M':
- if (count < maxsize - 2)
- {
- sprintf (&s[count], "%.2d",
- tim_p->tm_min);
- count += 2;
- }
- else
- return 0;
- break;
- case 'n':
- if (count < maxsize - 1)
- s[count++] = '\n';
- else
- return 0;
- break;
- case 'p':
- if (count < maxsize - 2)
- {
- if (tim_p->tm_hour < 12)
- s[count++] = 'A';
- else
- s[count++] = 'P';
-
- s[count++] = 'M';
- }
- else
- return 0;
- break;
- case 'r':
- if (count < maxsize - 11)
- {
- if (tim_p->tm_hour == 0 ||
- tim_p->tm_hour == 12)
- {
- s[count++] = '1';
- s[count++] = '2';
- }
- else
- {
- sprintf (&s[count], "%.2d", tim_p->tm_hour % 12);
- count += 2;
- }
- s[count++] = ':';
- sprintf (&s[count], "%.2d",
- tim_p->tm_min);
- count += 2;
- s[count++] = ':';
- sprintf (&s[count], "%.2d",
- tim_p->tm_sec);
- count += 2;
- s[count++] = ' ';
- if (tim_p->tm_hour < 12)
- s[count++] = 'A';
- else
- s[count++] = 'P';
-
- s[count++] = 'M';
- }
- else
- return 0;
- break;
- case 'R':
- if (count < maxsize - 5)
- {
- sprintf (&s[count], "%.2d:%.2d", tim_p->tm_hour, tim_p->tm_min);
- count += 5;
- }
- else
- return 0;
- break;
- case 'S':
- if (count < maxsize - 2)
- {
- sprintf (&s[count], "%.2d",
- tim_p->tm_sec);
- count += 2;
- }
- else
- return 0;
- break;
- case 't':
- if (count < maxsize - 1)
- s[count++] = '\t';
- else
- return 0;
- break;
- case 'T':
- case 'X':
- if (count < maxsize - 8)
- {
- sprintf (&s[count], "%.2d:%.2d:%.2d", tim_p->tm_hour,
- tim_p->tm_min, tim_p->tm_sec);
- count += 8;
- }
- else
- return 0;
- break;
- case 'u':
- if (count < maxsize - 1)
- {
- if (tim_p->tm_wday == 0)
- s[count++] = '7';
- else
- s[count++] = '0' + tim_p->tm_wday;
- }
- else
- return 0;
- break;
- case 'U':
- if (count < maxsize - 2)
- {
- sprintf (&s[count], "%.2d",
- (tim_p->tm_yday + 7 -
- tim_p->tm_wday) / 7);
- count += 2;
- }
- else
- return 0;
- break;
- case 'V':
- if (count < maxsize - 2)
- {
- int adjust = iso_year_adjust (tim_p);
- int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
- int week = (tim_p->tm_yday + 10 - wday) / 7;
- if (adjust > 0)
- week = 1;
- else if (adjust < 0)
- /* Previous year has 53 weeks if current year starts on
- Fri, and also if current year starts on Sat and
- previous year was leap year. */
- week = 52 + (4 >= (wday - tim_p->tm_yday
- - isleap (tim_p->tm_year
- + (YEAR_BASE - 1
- - (tim_p->tm_year < 0
- ? 0 : 2000)))));
- sprintf (&s[count], "%.2d", week);
- count += 2;
- }
- else
- return 0;
- break;
- case 'w':
- if (count < maxsize - 1)
- s[count++] = '0' + tim_p->tm_wday;
- else
- return 0;
- break;
- case 'W':
- if (count < maxsize - 2)
- {
- int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
- sprintf (&s[count], "%.2d",
- (tim_p->tm_yday + 7 - wday) / 7);
- count += 2;
- }
- else
- return 0;
- break;
- case 'y':
- if (count < maxsize - 2)
- {
- /* Be careful of both overflow and negative years, thanks to
- the asymmetric range of years. */
- int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
- : abs (tim_p->tm_year + YEAR_BASE) % 100;
- sprintf (&s[count], "%.2d", year);
- count += 2;
- }
- else
- return 0;
- break;
- case 'Y':
- {
- /* Length is not known because of %C%y, so recurse. */
- size_t adjust = strftime (&s[count], maxsize - count,
- "%C%y", tim_p);
- if (adjust > 0)
- count += adjust;
- else
- return 0;
- }
- break;
- case 'z':
-#ifndef _WIN32_WCE
- if (tim_p->tm_isdst >= 0)
- {
- if (count < maxsize - 5)
- {
- long offset;
- __tzinfo_type *tz = __gettzinfo ();
- TZ_LOCK;
- /* The sign of this is exactly opposite the envvar TZ. We
- could directly use the global _timezone for tm_isdst==0,
- but have to use __tzrule for daylight savings. */
- offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
- TZ_UNLOCK;
- sprintf (&s[count], "%+03ld%.2ld", offset / SECSPERHOUR,
- labs (offset / SECSPERMIN) % 60L);
- count += 5;
- }
- else
- return 0;
- }
- break;
-#endif
- case 'Z':
- if (tim_p->tm_isdst >= 0)
- {
- int size;
- TZ_LOCK;
- size = strlen(_tzname[tim_p->tm_isdst > 0]);
- for (i = 0; i < size; i++)
- {
- if (count < maxsize - 1)
- s[count++] = _tzname[tim_p->tm_isdst > 0][i];
- else
- {
- TZ_UNLOCK;
- return 0;
- }
- }
- TZ_UNLOCK;
- }
- break;
- case '%':
- if (count < maxsize - 1)
- s[count++] = '%';
- else
- return 0;
- break;
- }
- if (*format)
- format++;
- else
- break;
- }
- if (maxsize)
- s[count] = '\0';
-
- return count;
-}
diff --git a/vendor/shttpd/compat_wince.h b/vendor/shttpd/compat_wince.h
deleted file mode 100644
index 651ec50..0000000
--- a/vendor/shttpd/compat_wince.h
+++ /dev/null
@@ -1,145 +0,0 @@
-
-#ifndef INCLUDE_WINCE_COMPAT_H
-#define INCLUDE_WINCE_COMPAT_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*** ANSI C library ***/
-
-/* Missing ANSI C definitions */
-
-#define BUFSIZ 4096
-
-#define ENOMEM ERROR_NOT_ENOUGH_MEMORY
-#define EBADF ERROR_INVALID_HANDLE
-#define EINVAL ERROR_INVALID_PARAMETER
-#define ENOENT ERROR_FILE_NOT_FOUND
-#define ERANGE ERROR_INSUFFICIENT_BUFFER
-#define EINTR WSAEINTR
-
-/*
- * Because we need a per-thread errno, we define a function
- * pointer that we can call to return a pointer to the errno
- * for the current thread. Then we define a macro for errno
- * that dereferences this function's result.
- *
- * This makes it syntactically just like the "real" errno.
- *
- * Using a function pointer allows us to use a very fast
- * function when there are no threads running and a slower
- * function when there are multiple threads running.
- */
-void __WinCE_Errno_New_Thread(int *Errno_Pointer);
-void __WinCE_Errno_Thread_Exit(void);
-extern int *(*__WinCE_Errno_Pointer_Function)(void);
-
-#define errno (*(*__WinCE_Errno_Pointer_Function)())
-
-char *strerror(int errnum);
-
-struct tm {
- int tm_sec; /* seconds after the minute - [0,59] */
- int tm_min; /* minutes after the hour - [0,59] */
- int tm_hour; /* hours since midnight - [0,23] */
- int tm_mday; /* day of the month - [1,31] */
- int tm_mon; /* months since January - [0,11] */
- int tm_year; /* years since 1900 */
- int tm_wday; /* days since Sunday - [0,6] */
- int tm_yday; /* days since January 1 - [0,365] */
- int tm_isdst; /* daylight savings time flag */
-};
-
-struct tm *gmtime(const time_t *TimeP); /* for future use */
-struct tm *localtime(const time_t *TimeP);
-time_t mktime(struct tm *tm);
-time_t time(time_t *TimeP);
-
-size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *tim_p);
-
-int _wrename(const wchar_t *oldname, const wchar_t *newname);
-int _wremove(const wchar_t *filename);
-
-/* Environment variables are not supported */
-#define getenv(x) (NULL)
-
-/* Redefine fileno so that it returns an integer */
-#undef fileno
-#define fileno(f) (int)_fileno(f)
-
-/* Signals are not supported */
-#define signal(num, handler) (0)
-#define SIGTERM 0
-#define SIGINT 0
-
-
-/*** POSIX API ***/
-
-/* Missing POSIX definitions */
-
-#define FILENAME_MAX MAX_PATH
-
-struct _stat {
- unsigned long st_size;
- unsigned long st_ino;
- int st_mode;
- unsigned long st_atime;
- unsigned long st_mtime;
- unsigned long st_ctime;
- unsigned short st_dev;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
-};
-
-#define S_IFMT 0170000
-#define S_IFDIR 0040000
-#define S_IFREG 0100000
-#define S_IEXEC 0000100
-#define S_IWRITE 0000200
-#define S_IREAD 0000400
-
-#define _S_IFDIR S_IFDIR /* MSVCRT compatibilit */
-
-int _fstat(int handle, struct _stat *buffer);
-int _wstat(const wchar_t *path, struct _stat *buffer);
-
-#define stat _stat /* NOTE: applies to _stat() and also struct _stat */
-#define fstat _fstat
-
-#define O_RDWR (1<<0)
-#define O_RDONLY (2<<0)
-#define O_WRONLY (3<<0)
-#define O_MODE_MASK (3<<0)
-#define O_TRUNC (1<<2)
-#define O_EXCL (1<<3)
-#define O_CREAT (1<<4)
-#define O_BINARY 0
-
-int _wopen(const wchar_t *filename, int oflag, ...);
-int _close(int handle);
-int _write(int handle, const void *buffer, unsigned int count);
-int _read(int handle, void *buffer, unsigned int count);
-long _lseek(int handle, long offset, int origin);
-
-#define close _close
-#define write _write
-#define read _read
-#define lseek _lseek
-
-/* WinCE has only a Unicode version of this function */
-FILE *fdopen(int handle, const char *mode);
-
-int _wmkdir(const wchar_t *dirname);
-
-/* WinCE has no concept of current directory so we return a constant path */
-wchar_t *_wgetcwd(wchar_t *buffer, int maxlen);
-
-#define freopen(path, mode, stream) assert(0)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* INCLUDE_WINCE_COMPAT_H */
diff --git a/vendor/shttpd/config.h b/vendor/shttpd/config.h
deleted file mode 100644
index 875bbf3..0000000
--- a/vendor/shttpd/config.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#ifndef CONFIG_HEADER_DEFINED
-#define CONFIG_HEADER_DEFINED
-
-#undef VERSION
-#define VERSION "1.42" /* Version */
-#define CONFIG_FILE "shttpd.conf" /* Configuration file */
-#define HTPASSWD ".htpasswd" /* Passwords file name */
-#define URI_MAX 16384 /* Default max request size */
-#define LISTENING_PORTS "80" /* Default listening ports */
-#define INDEX_FILES "index.html,index.htm,index.php,index.cgi"
-#define CGI_EXT "cgi,pl,php" /* Default CGI extensions */
-#define SSI_EXT "shtml,shtm" /* Default SSI extensions */
-#define REALM "mydomain.com" /* Default authentication realm */
-#define DELIM_CHARS "," /* Separators for lists */
-#define EXPIRE_TIME 3600 /* Expiration time, seconds */
-#define ENV_MAX 4096 /* Size of environment block */
-#define CGI_ENV_VARS 64 /* Maximum vars passed to CGI */
-#define SERVICE_NAME "SHTTPD " VERSION /* NT service name */
-
-#endif /* CONFIG_HEADER_DEFINED */
diff --git a/vendor/shttpd/defs.h b/vendor/shttpd/defs.h
deleted file mode 100644
index 120de35..0000000
--- a/vendor/shttpd/defs.h
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#ifndef DEFS_HEADER_DEFINED
-#define DEFS_HEADER_DEFINED
-
-#include "std_includes.h"
-#include "llist.h"
-#include "io.h"
-#include "md5.h"
-#include "config.h"
-#include "shttpd.h"
-
-#define NELEMS(ar) (sizeof(ar) / sizeof(ar[0]))
-
-#ifdef _DEBUG
-#define DBG(x) do { printf x ; putchar('\n'); fflush(stdout); } while (0)
-#else
-#define DBG(x)
-#endif /* DEBUG */
-
-/*
- * Darwin prior to 7.0 and Win32 do not have socklen_t
- */
-#ifdef NO_SOCKLEN_T
-typedef int socklen_t;
-#endif /* NO_SOCKLEN_T */
-
-/*
- * For parsing. This guy represents a substring.
- */
-struct vec {
- const char *ptr;
- int len;
-};
-
-#if !defined(FALSE)
-enum {FALSE, TRUE};
-#endif /* !FALSE */
-
-enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD};
-enum {HDR_DATE, HDR_INT, HDR_STRING}; /* HTTP header types */
-enum {E_FATAL = 1, E_LOG = 2}; /* Flags for elog() function */
-typedef unsigned long big_int_t; /* Type for Content-Length */
-
-/*
- * Unified socket address
- */
-struct usa {
- socklen_t len;
- union {
- struct sockaddr sa;
- struct sockaddr_in sin;
- } u;
-};
-
-/*
- * This thing is aimed to hold values of any type.
- * Used to store parsed headers' values.
- */
-union variant {
- char *v_str;
- int v_int;
- big_int_t v_big_int;
- time_t v_time;
- void (*v_func)(void);
- void *v_void;
- struct vec v_vec;
-};
-
-/*
- * This is used only in embedded configuration. This structure holds a
- * registered URI, associated callback function with callback data.
- * For non-embedded compilation shttpd_callback_t is not defined, so
- * we use union variant to keep the compiler silent.
- */
-struct registered_uri {
- struct llhead link;
- const char *uri;
- union variant callback;
- void *callback_data;
-};
-
-/*
- * User may want to handle certain errors. This structure holds the
- * handlers for corresponding error codes.
- */
-struct error_handler {
- struct llhead link;
- int code;
- union variant callback;
- void *callback_data;
-};
-
-struct http_header {
- int len; /* Header name length */
- int type; /* Header type */
- size_t offset; /* Value placeholder */
- const char *name; /* Header name */
-};
-
-/*
- * This guy holds parsed HTTP headers
- */
-struct headers {
- union variant cl; /* Content-Length: */
- union variant ct; /* Content-Type: */
- union variant connection; /* Connection: */
- union variant ims; /* If-Modified-Since: */
- union variant user; /* Remote user name */
- union variant auth; /* Authorization */
- union variant useragent; /* User-Agent: */
- union variant referer; /* Referer: */
- union variant cookie; /* Cookie: */
- union variant location; /* Location: */
- union variant range; /* Range: */
- union variant status; /* Status: */
- union variant transenc; /* Transfer-Encoding: */
-};
-
-/* Must go after union variant definition */
-#include "ssl.h"
-
-/*
- * The communication channel
- */
-union channel {
- int fd; /* Regular static file */
- int sock; /* Connected socket */
- struct {
- int sock; /* XXX important. must be first */
- SSL *ssl; /* shttpd_poll() assumes that */
- } ssl; /* SSL-ed socket */
- struct {
- DIR *dirp;
- char *path;
- } dir; /* Opened directory */
- struct {
- void *state; /* For keeping state */
- union variant func; /* User callback function */
- void *data; /* User defined parameters */
- } emb; /* Embedded, user callback */
-};
-
-struct stream;
-
-/*
- * IO class descriptor (file, directory, socket, SSL, CGI, etc)
- * These classes are defined in io_*.c files.
- */
-struct io_class {
- const char *name;
- int (*read)(struct stream *, void *buf, size_t len);
- int (*write)(struct stream *, const void *buf, size_t len);
- void (*close)(struct stream *);
-};
-
-/*
- * Data exchange stream. It is backed by some communication channel:
- * opened file, socket, etc. The 'read' and 'write' methods are
- * determined by a communication channel.
- */
-struct stream {
- struct conn *conn;
- union channel chan; /* Descriptor */
- struct io io; /* IO buffer */
- const struct io_class *io_class; /* IO class */
- int headers_len;
- big_int_t content_len;
- unsigned int flags;
-#define FLAG_HEADERS_PARSED 1
-#define FLAG_SSL_ACCEPTED 2
-#define FLAG_R 4 /* Can read in general */
-#define FLAG_W 8 /* Can write in general */
-#define FLAG_CLOSED 16
-#define FLAG_DONT_CLOSE 32
-#define FLAG_ALWAYS_READY 64 /* File, dir, user_func */
-#define FLAG_SUSPEND 128
-};
-
-struct worker {
- struct llhead link;
- int num_conns; /* Num of active connections */
- int exit_flag; /* Ditto - exit flag */
- int ctl[2]; /* Control socket pair */
- struct shttpd_ctx *ctx; /* Context reference */
- struct llhead connections; /* List of connections */
-};
-
-struct conn {
- struct llhead link; /* Connections chain */
- struct worker *worker; /* Worker this conn belongs to */
- struct shttpd_ctx *ctx; /* Context this conn belongs to */
- struct usa sa; /* Remote socket address */
- time_t birth_time; /* Creation time */
- time_t expire_time; /* Expiration time */
-
- int loc_port; /* Local port */
- int status; /* Reply status code */
- int method; /* Request method */
- char *uri; /* Decoded URI */
- unsigned long major_version; /* Major HTTP version number */
- unsigned long minor_version; /* Minor HTTP version number */
- char *request; /* Request line */
- char *headers; /* Request headers */
- char *query; /* QUERY_STRING part of the URI */
- char *path_info; /* PATH_INFO thing */
- struct vec mime_type; /* Mime type */
-
- struct headers ch; /* Parsed client headers */
-
- struct stream loc; /* Local stream */
- struct stream rem; /* Remote stream */
-
-#if !defined(NO_SSI)
- void *ssi; /* SSI descriptor */
-#endif /* NO_SSI */
-};
-
-enum {
- OPT_ROOT, OPT_INDEX_FILES, OPT_PORTS, OPT_DIR_LIST,
- OPT_CGI_EXTENSIONS, OPT_CGI_INTERPRETER, OPT_CGI_ENVIRONMENT,
- OPT_SSI_EXTENSIONS, OPT_AUTH_REALM, OPT_AUTH_GPASSWD,
- OPT_AUTH_PUT, OPT_ACCESS_LOG, OPT_ERROR_LOG, OPT_MIME_TYPES,
- OPT_SSL_CERTIFICATE, OPT_ALIASES, OPT_ACL, OPT_INETD, OPT_UID,
- OPT_CFG_URI, OPT_PROTECT, OPT_SERVICE, OPT_HIDE, OPT_THREADS,
- NUM_OPTIONS
-};
-
-/*
- * SHTTPD context
- */
-struct shttpd_ctx {
- SSL_CTX *ssl_ctx; /* SSL context */
-
- struct llhead registered_uris;/* User urls */
- struct llhead error_handlers; /* Embedded error handlers */
- struct llhead acl; /* Access control list */
- struct llhead ssi_funcs; /* SSI callback functions */
- struct llhead listeners; /* Listening sockets */
- struct llhead workers; /* Worker workers */
-
- FILE *access_log; /* Access log stream */
- FILE *error_log; /* Error log stream */
-
- char *options[NUM_OPTIONS]; /* Configurable options */
-#if defined(__rtems__)
- rtems_id mutex;
-#endif /* _WIN32 */
-};
-
-struct listener {
- struct llhead link;
- struct shttpd_ctx *ctx; /* Context that socket belongs */
- int sock; /* Listening socket */
- int is_ssl; /* Should be SSL-ed */
-};
-
-/* Types of messages that could be sent over the control socket */
-enum {CTL_PASS_SOCKET, CTL_WAKEUP};
-
-/*
- * In SHTTPD, list of values are represented as comma or space separated
- * string. For example, list of CGI extensions can be represented as
- * ".cgi,.php,.pl", or ".cgi .php .pl". The macro that follows allows to
- * loop through the individual values in that list.
- *
- * A "const char *" pointer and size_t variable must be passed to the macro.
- * Spaces or commas can be used as delimiters (macro DELIM_CHARS).
- *
- * In every iteration of the loop, "s" points to the current value, and
- * "len" specifies its length. The code inside loop must not change
- * "s" and "len" parameters.
- */
-#define FOR_EACH_WORD_IN_LIST(s,len) \
- for (; s != NULL && (len = strcspn(s, DELIM_CHARS)) != 0; \
- s += len, s+= strspn(s, DELIM_CHARS))
-
-/*
- * IPv4 ACL entry. Specifies subnet with deny/allow flag
- */
-struct acl {
- struct llhead link;
- uint32_t ip; /* IP, in network byte order */
- uint32_t mask; /* Also in network byte order */
- int flag; /* Either '+' or '-' */
-};
-
-/*
- * shttpd.c
- */
-extern time_t _shttpd_current_time; /* Current UTC time */
-extern int _shttpd_tz_offset; /* Offset from GMT time zone */
-extern const struct vec _shttpd_known_http_methods[];
-
-extern void _shttpd_stop_stream(struct stream *stream);
-extern int _shttpd_url_decode(const char *, int, char *dst, int);
-extern void _shttpd_send_server_error(struct conn *, int, const char *);
-extern int _shttpd_get_headers_len(const char *buf, size_t buflen);
-extern void _shttpd_parse_headers(const char *s, int, struct headers *);
-extern int _shttpd_is_true(const char *str);
-extern int _shttpd_socketpair(int pair[2]);
-extern void _shttpd_get_mime_type(struct shttpd_ctx *,
- const char *, int, struct vec *);
-
-#define IS_TRUE(ctx, opt) _shttpd_is_true((ctx)->options[opt])
-
-/*
- * config.c
- */
-extern void _shttpd_usage(const char *prog);
-
-/*
- * log.c
- */
-extern void _shttpd_elog(int flags, struct conn *c, const char *fmt, ...);
-extern void _shttpd_log_access(FILE *fp, const struct conn *c);
-
-/*
- * string.c
- */
-extern void _shttpd_strlcpy(register char *, register const char *, size_t);
-extern int _shttpd_strncasecmp(register const char *,
- register const char *, size_t);
-extern char *_shttpd_strndup(const char *ptr, size_t len);
-extern char *_shttpd_strdup(const char *str);
-extern int _shttpd_snprintf(char *buf, size_t len, const char *fmt, ...);
-extern int _shttpd_match_extension(const char *path, const char *ext_list);
-
-/*
- * compat_*.c
- */
-extern void _shttpd_set_close_on_exec(int fd);
-extern int _shttpd_set_non_blocking_mode(int fd);
-extern int _shttpd_stat(const char *, struct stat *stp);
-extern int _shttpd_open(const char *, int flags, int mode);
-extern int _shttpd_remove(const char *);
-extern int _shttpd_rename(const char *, const char *);
-extern int _shttpd_mkdir(const char *, int);
-extern char * _shttpd_getcwd(char *, int);
-extern int _shttpd_spawn_process(struct conn *c, const char *prog,
- char *envblk, char *envp[], int sock, const char *dir);
-
-extern int _shttpd_set_nt_service(struct shttpd_ctx *, const char *);
-extern int _shttpd_set_systray(struct shttpd_ctx *, const char *);
-extern void _shttpd_try_to_run_as_nt_service(void);
-
-/*
- * io_*.c
- */
-extern const struct io_class _shttpd_io_file;
-extern const struct io_class _shttpd_io_socket;
-extern const struct io_class _shttpd_io_ssl;
-extern const struct io_class _shttpd_io_cgi;
-extern const struct io_class _shttpd_io_dir;
-extern const struct io_class _shttpd_io_embedded;
-extern const struct io_class _shttpd_io_ssi;
-
-extern int _shttpd_put_dir(const char *path);
-extern void _shttpd_get_dir(struct conn *c);
-extern void _shttpd_get_file(struct conn *c, struct stat *stp);
-extern void _shttpd_ssl_handshake(struct stream *stream);
-extern void _shttpd_setup_embedded_stream(struct conn *,
- union variant, void *);
-extern struct registered_uri *_shttpd_is_registered_uri(struct shttpd_ctx *,
- const char *uri);
-extern void _shttpd_do_ssi(struct conn *);
-extern void _shttpd_ssi_func_destructor(struct llhead *lp);
-
-/*
- * auth.c
- */
-extern int _shttpd_check_authorization(struct conn *c, const char *path);
-extern int _shttpd_is_authorized_for_put(struct conn *c);
-extern void _shttpd_send_authorization_request(struct conn *c);
-extern int _shttpd_edit_passwords(const char *fname, const char *domain,
- const char *user, const char *pass);
-
-/*
- * cgi.c
- */
-extern int _shttpd_run_cgi(struct conn *c, const char *prog);
-extern void _shttpd_do_cgi(struct conn *c);
-
-#define CGI_REPLY "HTTP/1.1 OK\r\n"
-#define CGI_REPLY_LEN (sizeof(CGI_REPLY) - 1)
-
-#endif /* DEFS_HEADER_DEFINED */
diff --git a/vendor/shttpd/io.h b/vendor/shttpd/io.h
deleted file mode 100644
index d774cc2..0000000
--- a/vendor/shttpd/io.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#ifndef IO_HEADER_INCLUDED
-#define IO_HEADER_INCLUDED
-
-#include <assert.h>
-#include <stddef.h>
-
-/*
- * I/O buffer descriptor
- */
-struct io {
- char *buf; /* IO Buffer */
- size_t size; /* IO buffer size */
- size_t head; /* Bytes read */
- size_t tail; /* Bytes written */
- size_t total; /* Total bytes read */
-};
-
-static __inline void
-io_clear(struct io *io)
-{
- assert(io->buf != NULL);
- assert(io->size > 0);
- io->total = io->tail = io->head = 0;
-}
-
-static __inline char *
-io_space(struct io *io)
-{
- assert(io->buf != NULL);
- assert(io->size > 0);
- assert(io->head <= io->size);
- return (io->buf + io->head);
-}
-
-static __inline char *
-io_data(struct io *io)
-{
- assert(io->buf != NULL);
- assert(io->size > 0);
- assert(io->tail <= io->size);
- return (io->buf + io->tail);
-}
-
-static __inline size_t
-io_space_len(const struct io *io)
-{
- assert(io->buf != NULL);
- assert(io->size > 0);
- assert(io->head <= io->size);
- return (io->size - io->head);
-}
-
-static __inline size_t
-io_data_len(const struct io *io)
-{
- assert(io->buf != NULL);
- assert(io->size > 0);
- assert(io->head <= io->size);
- assert(io->tail <= io->head);
- return (io->head - io->tail);
-}
-
-static __inline void
-io_inc_tail(struct io *io, size_t n)
-{
- assert(io->buf != NULL);
- assert(io->size > 0);
- assert(io->tail <= io->head);
- assert(io->head <= io->size);
- io->tail += n;
- assert(io->tail <= io->head);
- if (io->tail == io->head)
- io->head = io->tail = 0;
-}
-
-static __inline void
-io_inc_head(struct io *io, size_t n)
-{
- assert(io->buf != NULL);
- assert(io->size > 0);
- assert(io->tail <= io->head);
- io->head += n;
- io->total += n;
- assert(io->head <= io->size);
-}
-
-#endif /* IO_HEADER_INCLUDED */
diff --git a/vendor/shttpd/io_cgi.c b/vendor/shttpd/io_cgi.c
deleted file mode 100644
index b41c600..0000000
--- a/vendor/shttpd/io_cgi.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-static int
-write_cgi(struct stream *stream, const void *buf, size_t len)
-{
- assert(stream->chan.sock != -1);
- assert(stream->flags & FLAG_W);
-
- return (send(stream->chan.sock, buf, len, 0));
-}
-
-static int
-read_cgi(struct stream *stream, void *buf, size_t len)
-{
- struct headers parsed;
- char status[4];
- int n;
-
- assert(stream->chan.sock != -1);
- assert(stream->flags & FLAG_R);
-
- stream->flags &= ~FLAG_DONT_CLOSE;
-
- n = recv(stream->chan.sock, buf, len, 0);
-
- if (stream->flags & FLAG_HEADERS_PARSED)
- return (n);
-
- if (n <= 0 && ERRNO != EWOULDBLOCK) {
- _shttpd_send_server_error(stream->conn, 500,
- "Error running CGI");
- return (n);
- }
-
- /*
- * CGI script may output Status: and Location: headers, which
- * may alter the status code. Buffer in headers, parse
- * them, send correct status code and then forward all data
- * from CGI script back to the remote end.
- * Reply line was alredy appended to the IO buffer in
- * decide_what_to_do(), with blank status code.
- */
-
- stream->flags |= FLAG_DONT_CLOSE;
- io_inc_head(&stream->io, n);
-
- stream->headers_len = _shttpd_get_headers_len(stream->io.buf,
- stream->io.head);
- if (stream->headers_len < 0) {
- stream->flags &= ~FLAG_DONT_CLOSE;
- _shttpd_send_server_error(stream->conn, 500,
- "Bad headers sent");
- _shttpd_elog(E_LOG, stream->conn,
- "CGI script sent invalid headers: "
- "[%.*s]", stream->io.head - CGI_REPLY_LEN,
- stream->io.buf + CGI_REPLY_LEN);
- return (0);
- }
-
- /*
- * If we did not received full headers yet, we must not send any
- * data read from the CGI back to the client. Suspend sending by
- * setting tail = head, which tells that there is no data in IO buffer
- */
-
- if (stream->headers_len == 0) {
- stream->io.tail = stream->io.head;
- return (0);
- }
-
- /* Received all headers. Set status code for the connection. */
- (void) memset(&parsed, 0, sizeof(parsed));
- _shttpd_parse_headers(stream->io.buf, stream->headers_len, &parsed);
- stream->content_len = parsed.cl.v_big_int;
- stream->conn->status = (int) parsed.status.v_big_int;
-
- /* If script outputs 'Location:' header, set status code to 302 */
- if (parsed.location.v_vec.len > 0)
- stream->conn->status = 302;
-
- /*
- * If script did not output neither 'Location:' nor 'Status' headers,
- * set the default status code 200, which means 'success'.
- */
- if (stream->conn->status == 0)
- stream->conn->status = 200;
-
- /* Append the status line to the beginning of the output */
- (void) _shttpd_snprintf(status,
- sizeof(status), "%3d", stream->conn->status);
- (void) memcpy(stream->io.buf + 9, status, 3);
- DBG(("read_cgi: content len %lu status %s",
- stream->content_len, status));
-
- /* Next time, pass output directly back to the client */
- assert((big_int_t) stream->headers_len <= stream->io.total);
- stream->io.total -= stream->headers_len;
- stream->io.tail = 0;
- stream->flags |= FLAG_HEADERS_PARSED;
-
- /* Return 0 because we've already shifted the head */
- return (0);
-}
-
-static void
-close_cgi(struct stream *stream)
-{
- assert(stream->chan.sock != -1);
- (void) closesocket(stream->chan.sock);
-}
-
-const struct io_class _shttpd_io_cgi = {
- "cgi",
- read_cgi,
- write_cgi,
- close_cgi
-};
diff --git a/vendor/shttpd/io_dir.c b/vendor/shttpd/io_dir.c
deleted file mode 100644
index 7366398..0000000
--- a/vendor/shttpd/io_dir.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-/*
- * For a given PUT path, create all intermediate subdirectories
- * for given path. Return 0 if the path itself is a directory,
- * or -1 on error, 1 if OK.
- */
-int
-_shttpd_put_dir(const char *path)
-{
- char buf[FILENAME_MAX];
- const char *s, *p;
- struct stat st;
- size_t len;
-
- for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
- len = p - path;
- assert(len < sizeof(buf));
- (void) memcpy(buf, path, len);
- buf[len] = '\0';
-
- /* Try to create intermediate directory */
- if (_shttpd_stat(buf, &st) == -1 &&
- _shttpd_mkdir(buf, 0755) != 0)
- return (-1);
-
- /* Is path itself a directory ? */
- if (p[1] == '\0')
- return (0);
- }
-
- return (1);
-}
-
-static int
-read_dir(struct stream *stream, void *buf, size_t len)
-{
- static const char footer[] = "</table></body></html>\n";
-
- struct dirent *dp = NULL;
- char file[FILENAME_MAX], line[FILENAME_MAX + 512],
- size[64], mod[64];
- struct stat st;
- struct conn *c = stream->conn;
- int n, nwritten = 0;
- const char *slash = "";
-
- assert(stream->chan.dir.dirp != NULL);
- assert(stream->conn->uri[0] != '\0');
-
- do {
- if (len < sizeof(line))
- break;
-
- if ((dp = readdir(stream->chan.dir.dirp)) == NULL)
- break;
- DBG(("read_dir: %s", dp->d_name));
-
- /* Do not show current dir and passwords file */
- if (strcmp(dp->d_name, ".") == 0 ||
- strcmp(dp->d_name, HTPASSWD) == 0)
- continue;
-
- (void) _shttpd_snprintf(file, sizeof(file),
- "%s%s%s", stream->chan.dir.path, slash, dp->d_name);
- (void) _shttpd_stat(file, &st);
- if (S_ISDIR(st.st_mode)) {
- _shttpd_snprintf(size,sizeof(size),"%s","<DIR>");
- } else {
- if (st.st_size < 1024)
- (void) _shttpd_snprintf(size, sizeof(size),
- "%lu", (unsigned long) st.st_size);
- else if (st.st_size < 1024 * 1024)
- (void) _shttpd_snprintf(size,
- sizeof(size), "%luk",
- (unsigned long) (st.st_size >> 10) + 1);
- else
- (void) _shttpd_snprintf(size, sizeof(size),
- "%.1fM", (float) st.st_size / 1048576);
- }
- (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
- localtime(&st.st_mtime));
-
- n = _shttpd_snprintf(line, sizeof(line),
- "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
- "<td> %s</td><td> %s</td></tr>\n",
- c->uri, slash, dp->d_name, dp->d_name,
- S_ISDIR(st.st_mode) ? "/" : "", mod, size);
- (void) memcpy(buf, line, n);
- buf = (char *) buf + n;
- nwritten += n;
- len -= n;
- } while (dp != NULL);
-
- /* Append proper HTML footer for the page */
- if (dp == NULL && len >= sizeof(footer)) {
- (void) memcpy(buf, footer, sizeof(footer));
- nwritten += sizeof(footer);
- stream->flags |= FLAG_CLOSED;
- }
-
- return (nwritten);
-}
-
-static void
-close_dir(struct stream *stream)
-{
- assert(stream->chan.dir.dirp != NULL);
- assert(stream->chan.dir.path != NULL);
- (void) closedir(stream->chan.dir.dirp);
- free(stream->chan.dir.path);
-}
-
-void
-_shttpd_get_dir(struct conn *c)
-{
- if ((c->loc.chan.dir.dirp = opendir(c->loc.chan.dir.path)) == NULL) {
- (void) free(c->loc.chan.dir.path);
- _shttpd_send_server_error(c, 500, "Cannot open directory");
- } else {
- c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
- "HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Type: text/html; charset=utf-8\r\n\r\n"
- "<html><head><title>Index of %s</title>"
- "<style>th {text-align: left;}</style></head>"
- "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
- "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
- "<tr><td colspan=\"3\"><hr></td></tr>",
- c->uri, c->uri);
- io_clear(&c->rem.io);
- c->status = 200;
- c->loc.io_class = &_shttpd_io_dir;
- c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
- }
-}
-
-const struct io_class _shttpd_io_dir = {
- "dir",
- read_dir,
- NULL,
- close_dir
-};
diff --git a/vendor/shttpd/io_emb.c b/vendor/shttpd/io_emb.c
deleted file mode 100644
index 468180b..0000000
--- a/vendor/shttpd/io_emb.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-const char *
-shttpd_version(void)
-{
- return (VERSION);
-}
-
-static void
-call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func)
-{
- arg->priv = c;
- arg->state = c->loc.chan.emb.state;
- arg->out.buf = io_space(&c->loc.io);
- arg->out.len = io_space_len(&c->loc.io);
- arg->out.num_bytes = 0;
- arg->in.buf = io_data(&c->rem.io);;
- arg->in.len = io_data_len(&c->rem.io);
- arg->in.num_bytes = 0;
-
- if (io_data_len(&c->rem.io) >= c->rem.io.size)
- arg->flags |= SHTTPD_POST_BUFFER_FULL;
-
- if (c->rem.content_len > 0 && c->rem.io.total < c->rem.content_len)
- arg->flags |= SHTTPD_MORE_POST_DATA;
-
- func(arg);
-
- io_inc_head(&c->loc.io, arg->out.num_bytes);
- io_inc_tail(&c->rem.io, arg->in.num_bytes);
- c->loc.chan.emb.state = arg->state; /* Save state */
-
- /*
- * If callback finished output, that means it did all cleanup.
- * If the connection is terminated unexpectedly, we canna call
- * the callback via the stream close() method from disconnect.
- * However, if cleanup is already done, we set close() method to
- * NULL, to prevent the call from disconnect().
- */
-
- if (arg->flags & SHTTPD_END_OF_OUTPUT)
- c->loc.flags &= ~FLAG_DONT_CLOSE;
- else
- c->loc.flags |= FLAG_DONT_CLOSE;
-
- if (arg->flags & SHTTPD_SUSPEND)
- c->loc.flags |= FLAG_SUSPEND;
-}
-
-static int
-do_embedded(struct stream *stream, void *buf, size_t len)
-{
- struct shttpd_arg arg;
- buf = NULL; len = 0; /* Squash warnings */
-
- arg.user_data = stream->conn->loc.chan.emb.data;
- arg.flags = 0;
-
- call_user(stream->conn, &arg, (shttpd_callback_t)
- stream->conn->loc.chan.emb.func.v_func);
-
- return (0);
-}
-
-static void
-close_embedded(struct stream *stream)
-{
- struct shttpd_arg arg;
- struct conn *c = stream->conn;
-
- arg.flags = SHTTPD_CONNECTION_ERROR;
- arg.user_data = c->loc.chan.emb.data;
-
- /*
- * Do not call the user function if SHTTPD_END_OF_OUTPUT was set,
- * i.e. the callback already terminated correctly
- */
- if (stream->flags & FLAG_DONT_CLOSE)
- call_user(stream->conn, &arg, (shttpd_callback_t)
- c->loc.chan.emb.func.v_func);
-}
-
-size_t
-shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
-{
- char *buf = arg->out.buf + arg->out.num_bytes;
- int buflen = arg->out.len - arg->out.num_bytes, len = 0;
- va_list ap;
-
- if (buflen > 0) {
- va_start(ap, fmt);
- len = vsnprintf(buf, buflen, fmt, ap);
- va_end(ap);
-
- if (len < 0 || len > buflen)
- len = buflen;
- arg->out.num_bytes += len;
- }
-
- return (len);
-}
-
-const char *
-shttpd_get_header(struct shttpd_arg *arg, const char *header_name)
-{
- struct conn *c = arg->priv;
- char *p, *s, *e;
- size_t len;
-
- p = c->headers;
- e = c->request + c->rem.headers_len;
- len = strlen(header_name);
-
- while (p < e) {
- if ((s = strchr(p, '\n')) != NULL)
- s[s[-1] == '\r' ? -1 : 0] = '\0';
- if (_shttpd_strncasecmp(header_name, p, len) == 0)
- return (p + len + 2);
-
- p += strlen(p) + 1;
- }
-
- return (NULL);
-}
-
-const char *
-shttpd_get_env(struct shttpd_arg *arg, const char *env_name)
-{
- struct conn *c = arg->priv;
- struct vec *vec;
-
- if (strcmp(env_name, "REQUEST_METHOD") == 0) {
- return (_shttpd_known_http_methods[c->method].ptr);
- } else if (strcmp(env_name, "REQUEST_URI") == 0) {
- return (c->uri);
- } else if (strcmp(env_name, "QUERY_STRING") == 0) {
- return (c->query);
- } else if (strcmp(env_name, "REMOTE_USER") == 0) {
- vec = &c->ch.user.v_vec;
- if (vec->len > 0) {
- ((char *) vec->ptr)[vec->len] = '\0';
- return (vec->ptr);
- }
- } else if (strcmp(env_name, "REMOTE_ADDR") == 0) {
- return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */
- }
-
- return (NULL);
-}
-
-void
-shttpd_get_http_version(struct shttpd_arg *arg,
- unsigned long *major, unsigned long *minor)
-{
- struct conn *c = arg->priv;
-
- *major = c->major_version;
- *minor = c->minor_version;
-}
-
-void
-shttpd_register_uri(struct shttpd_ctx *ctx,
- const char *uri, shttpd_callback_t callback, void *data)
-{
- struct registered_uri *e;
-
- if ((e = malloc(sizeof(*e))) != NULL) {
- e->uri = _shttpd_strdup(uri);
- e->callback.v_func = (void (*)(void)) callback;
- e->callback_data = data;
- LL_TAIL(&ctx->registered_uris, &e->link);
- }
-}
-
-int
-shttpd_get_var(const char *var, const char *buf, int buf_len,
- char *value, int value_len)
-{
- const char *p, *e, *s;
- size_t var_len;
-
- var_len = strlen(var);
- e = buf + buf_len; /* End of QUERY_STRING buffer */
-
- /* buf is "var1=val1&var2=val2...". Find variable first */
- for (p = buf; p + var_len < e; p++)
- if ((p == buf || p[-1] == '&') &&
- p[var_len] == '=' &&
- !_shttpd_strncasecmp(var, p, var_len)) {
-
- /* Point 'p' to var value, 's' to the end of value */
- p += var_len + 1;
- if ((s = memchr(p, '&', e - p)) == NULL)
- s = e;
-
- /* URL-decode value. Return result length */
- return (_shttpd_url_decode(p, s - p, value, value_len));
- }
-
- return (-1);
-}
-
-static int
-match_regexp(const char *regexp, const char *text)
-{
- if (*regexp == '\0')
- return (*text == '\0');
-
- if (*regexp == '*')
- do {
- if (match_regexp(regexp + 1, text))
- return (1);
- } while (*text++ != '\0');
-
- if (*text != '\0' && *regexp == *text)
- return (match_regexp(regexp + 1, text + 1));
-
- return (0);
-}
-
-struct registered_uri *
-_shttpd_is_registered_uri(struct shttpd_ctx *ctx, const char *uri)
-{
- struct llhead *lp;
- struct registered_uri *reg_uri;
-
- LL_FOREACH(&ctx->registered_uris, lp) {
- reg_uri = LL_ENTRY(lp, struct registered_uri, link);
- if (match_regexp(reg_uri->uri, uri))
- return (reg_uri);
- }
-
- return (NULL);
-}
-
-void
-_shttpd_setup_embedded_stream(struct conn *c, union variant func, void *data)
-{
- c->loc.chan.emb.state = NULL;
- c->loc.chan.emb.func = func;
- c->loc.chan.emb.data = data;
- c->loc.io_class = &_shttpd_io_embedded;
- c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY;
-}
-
-void
-shttpd_handle_error(struct shttpd_ctx *ctx, int code,
- shttpd_callback_t func, void *data)
-{
- struct error_handler *e;
-
- if ((e = malloc(sizeof(*e))) != NULL) {
- e->code = code;
- e->callback.v_func = (void (*)(void)) func;
- e->callback_data = data;
- LL_TAIL(&ctx->error_handlers, &e->link);
- }
-}
-
-void
-shttpd_wakeup(const void *priv)
-{
- const struct conn *conn = priv;
- char buf[sizeof(int) + sizeof(void *)];
- int cmd = CTL_WAKEUP;
-
-#if 0
- conn->flags &= ~SHTTPD_SUSPEND;
-#endif
- (void) memcpy(buf, &cmd, sizeof(cmd));
- (void) memcpy(buf + sizeof(cmd), conn, sizeof(conn));
-
- (void) send(conn->worker->ctl[1], buf, sizeof(buf), 0);
-}
-
-const struct io_class _shttpd_io_embedded = {
- "embedded",
- do_embedded,
- (int (*)(struct stream *, const void *, size_t)) do_embedded,
- close_embedded
-};
diff --git a/vendor/shttpd/io_file.c b/vendor/shttpd/io_file.c
deleted file mode 100644
index 674e455..0000000
--- a/vendor/shttpd/io_file.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-static int
-write_file(struct stream *stream, const void *buf, size_t len)
-{
- struct stat st;
- struct stream *rem = &stream->conn->rem;
- int n, fd = stream->chan.fd;
-
- assert(fd != -1);
- n = write(fd, buf, len);
-
- DBG(("put_file(%p, %d): %d bytes", (void *) stream, (int) len, n));
-
- if (n <= 0 || (rem->io.total >= (big_int_t) rem->content_len)) {
- (void) fstat(fd, &st);
- stream->io.head = stream->headers_len =
- _shttpd_snprintf(stream->io.buf,
- stream->io.size, "HTTP/1.1 %d OK\r\n"
- "Content-Length: %lu\r\nConnection: close\r\n\r\n",
- stream->conn->status, st.st_size);
- _shttpd_stop_stream(stream);
- }
-
- return (n);
-}
-
-static int
-read_file(struct stream *stream, void *buf, size_t len)
-{
-#ifdef USE_SENDFILE
- struct iovec vec;
- struct sf_hdtr hd = {&vec, 1, NULL, 0}, *hdp = &hd;
- int sock, fd, n;
- size_t nbytes;
- off_t sent;
-
- sock = stream->conn->rem.chan.sock;
- fd = stream->chan.fd;
-
- /* If this is the first call for this file, send the headers */
- vec.iov_base = stream->io.buf;
- vec.iov_len = stream->headers_len;
- if (stream->io.total > 0)
- hdp = NULL;
-
- nbytes = stream->content_len - stream->io.total;
- n = sendfile(fd, sock, lseek(fd, 0, SEEK_CUR), nbytes, hdp, &sent, 0);
-
- if (n == -1 && ERRNO != EAGAIN) {
- stream->flags &= ~FLAG_DONT_CLOSE;
- return (n);
- }
-
- stream->conn->ctx->out += sent;
-
- /* If we have sent the HTTP headers in this turn, clear them off */
- if (stream->io.total == 0) {
- assert(sent >= stream->headers_len);
- sent -= stream->headers_len;
- io_clear(&stream->io);
- }
-
- (void) lseek(fd, sent, SEEK_CUR);
- stream->io.total += sent;
- stream->flags |= FLAG_DONT_CLOSE;
-
- return (0);
-#endif /* USE_SENDFILE */
-
- assert(stream->chan.fd != -1);
- return (read(stream->chan.fd, buf, len));
-}
-
-static void
-close_file(struct stream *stream)
-{
- assert(stream->chan.fd != -1);
- (void) close(stream->chan.fd);
-}
-
-void
-_shttpd_get_file(struct conn *c, struct stat *stp)
-{
- char date[64], lm[64], etag[64], range[64] = "";
- size_t n, status = 200;
- unsigned long r1, r2;
- const char *fmt = "%a, %d %b %Y %H:%M:%S GMT", *msg = "OK";
- big_int_t cl; /* Content-Length */
-
- if (c->mime_type.len == 0)
- _shttpd_get_mime_type(c->ctx, c->uri,
- strlen(c->uri), &c->mime_type);
- cl = (big_int_t) stp->st_size;
-
- /* If Range: header specified, act accordingly */
- if (c->ch.range.v_vec.len > 0 &&
- (n = sscanf(c->ch.range.v_vec.ptr,"bytes=%lu-%lu",&r1, &r2)) > 0) {
- status = 206;
- (void) lseek(c->loc.chan.fd, r1, SEEK_SET);
- cl = n == 2 ? r2 - r1 + 1: cl - r1;
- (void) _shttpd_snprintf(range, sizeof(range),
- "Content-Range: bytes %lu-%lu/%lu\r\n",
- r1, r1 + cl - 1, (unsigned long) stp->st_size);
- msg = "Partial Content";
- }
-
- /* Prepare Etag, Date, Last-Modified headers */
- (void) strftime(date, sizeof(date),
- fmt, localtime(&_shttpd_current_time));
- (void) strftime(lm, sizeof(lm), fmt, localtime(&stp->st_mtime));
- (void) _shttpd_snprintf(etag, sizeof(etag), "%lx.%lx",
- (unsigned long) stp->st_mtime, (unsigned long) stp->st_size);
-
- /*
- * We do not do io_inc_head here, because it will increase 'total'
- * member in io. We want 'total' to be equal to the content size,
- * and exclude the headers length from it.
- */
- c->loc.io.head = c->loc.headers_len = _shttpd_snprintf(c->loc.io.buf,
- c->loc.io.size,
- "HTTP/1.1 %d %s\r\n"
- "Date: %s\r\n"
- "Last-Modified: %s\r\n"
- "Etag: \"%s\"\r\n"
- "Content-Type: %.*s\r\n"
- "Content-Length: %lu\r\n"
- "Accept-Ranges: bytes\r\n"
- "%s\r\n",
- status, msg, date, lm, etag,
- c->mime_type.len, c->mime_type.ptr, cl, range);
-
- c->status = status;
- c->loc.content_len = cl;
- c->loc.io_class = &_shttpd_io_file;
- c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
-
- if (c->method == METHOD_HEAD)
- _shttpd_stop_stream(&c->loc);
-}
-
-const struct io_class _shttpd_io_file = {
- "file",
- read_file,
- write_file,
- close_file
-};
diff --git a/vendor/shttpd/io_socket.c b/vendor/shttpd/io_socket.c
deleted file mode 100644
index 20bf207..0000000
--- a/vendor/shttpd/io_socket.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-static int
-read_socket(struct stream *stream, void *buf, size_t len)
-{
- assert(stream->chan.sock != -1);
- return (recv(stream->chan.sock, buf, len, 0));
-}
-
-static int
-write_socket(struct stream *stream, const void *buf, size_t len)
-{
- assert(stream->chan.sock != -1);
- return (send(stream->chan.sock, buf, len, 0));
-}
-
-static void
-close_socket(struct stream *stream)
-{
- assert(stream->chan.sock != -1);
- (void) closesocket(stream->chan.sock);
-}
-
-const struct io_class _shttpd_io_socket = {
- "socket",
- read_socket,
- write_socket,
- close_socket
-};
diff --git a/vendor/shttpd/io_ssi.c b/vendor/shttpd/io_ssi.c
deleted file mode 100644
index 1c15fc6..0000000
--- a/vendor/shttpd/io_ssi.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright (c) 2006,2007 Steven Johnson <sjohnson(a)sakuraindustries.com>
- * Copyright (c) 2007 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-#if !defined(NO_SSI)
-
-#define CMDBUFSIZ 512 /* SSI command buffer size */
-#define NEST_MAX 6 /* Maximum nesting level */
-
-struct ssi_func {
- struct llhead link;
- void *user_data;
- char *name;
- shttpd_callback_t func;
-};
-
-struct ssi_inc {
- int state; /* Buffering state */
- int cond; /* Conditional state */
- FILE *fp; /* Icluded file stream */
- char buf[CMDBUFSIZ]; /* SSI command buffer */
- size_t nbuf; /* Bytes in a command buffer */
- FILE *pipe; /* #exec stream */
- struct ssi_func func; /* #call function */
-};
-
-struct ssi {
- struct conn *conn; /* Connection we belong to */
- int nest; /* Current nesting level */
- struct ssi_inc incs[NEST_MAX]; /* Nested includes */
-};
-
-enum { SSI_PASS, SSI_BUF, SSI_EXEC, SSI_CALL };
-enum { SSI_GO, SSI_STOP }; /* Conditional states */
-
-static const struct vec st = {"<!--#", 5};
-
-void
-shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
- shttpd_callback_t func, void *user_data)
-{
- struct ssi_func *e;
-
- if ((e = malloc(sizeof(*e))) != NULL) {
- e->name = _shttpd_strdup(name);
- e->func = func;
- e->user_data = user_data;
- LL_TAIL(&ctx->ssi_funcs, &e->link);
- }
-}
-
-void
-_shttpd_ssi_func_destructor(struct llhead *lp)
-{
- struct ssi_func *e = LL_ENTRY(lp, struct ssi_func, link);
-
- free(e->name);
- free(e);
-}
-
-static const struct ssi_func *
-find_ssi_func(struct ssi *ssi, const char *name)
-{
- struct ssi_func *e;
- struct llhead *lp;
-
- LL_FOREACH(&ssi->conn->ctx->ssi_funcs, lp) {
- e = LL_ENTRY(lp, struct ssi_func, link);
- if (!strcmp(name, e->name))
- return (e);
- }
-
- return (NULL);
-}
-
-static void
-call(struct ssi *ssi, const char *name,
- struct shttpd_arg *arg, char *buf, int len)
-{
- const struct ssi_func *ssi_func;
-
- (void) memset(arg, 0, sizeof(*arg));
-
- /*
- * SSI function may be called with parameters. These parameters
- * are passed as arg->in.buf, arg->in.len vector.
- */
- arg->in.buf = strchr(name, ' ');
- if (arg->in.buf != NULL) {
- *arg->in.buf++ = '\0';
- arg->in.len = strlen(arg->in.buf);
- }
-
- if ((ssi_func = find_ssi_func(ssi, name)) != NULL) {
- arg->priv = ssi->conn;
- arg->user_data = ssi_func->user_data;
- arg->out.buf = buf;
- arg->out.len = len;
- ssi_func->func(arg);
- }
-}
-
-static int
-evaluate(struct ssi *ssi, const char *name)
-{
- struct shttpd_arg arg;
-
- call(ssi, name, &arg, NULL, 0);
-
- return (arg.flags & SHTTPD_SSI_EVAL_TRUE);
-}
-
-static void
-pass(struct ssi_inc *inc, void *buf, int *n)
-{
- if (inc->cond == SSI_GO) {
- (void) memcpy(buf, inc->buf, inc->nbuf);
- (*n) += inc->nbuf;
- }
- inc->nbuf = 0;
- inc->state = SSI_PASS;
-}
-
-static int
-get_path(struct conn *conn, const char *src,
- int src_len, char *dst, int dst_len)
-{
- static struct vec accepted[] = {
- {"\"", 1}, /* Relative to webserver CWD */
- {"file=\"", 6}, /* Relative to current URI */
- {"virtual=\"", 9}, /* Relative to document root */
- {NULL, 0},
- };
- struct vec *vec;
- const char *p, *root = conn->ctx->options[OPT_ROOT];
- int len;
-
- for (vec = accepted; vec->len > 0; vec++)
- if (src_len > vec->len && !memcmp(src, vec->ptr, vec->len)) {
- src += vec->len;
- src_len -= vec->len;
- if ((p = memchr(src, '"', src_len)) == NULL)
- break;
- if (vec->len == 6) {
- len = _shttpd_snprintf(dst, dst_len, "%s%c%s",
- root, DIRSEP, conn->uri);
- while (len > 0 && dst[len] != '/')
- len--;
- dst += len;
- dst_len -= len;
- } else if (vec->len == 9) {
- len = _shttpd_snprintf(dst, dst_len, "%s%c",
- root, DIRSEP);
- dst += len;
- dst_len -= len;
- }
- _shttpd_url_decode(src, p - src, dst, dst_len);
- return (1);
- }
-
- return (0);
-}
-
-static void
-do_include(struct ssi *ssi)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- char buf[FILENAME_MAX];
- FILE *fp;
-
- assert(inc->nbuf >= 13);
-
- if (inc->cond == SSI_STOP) {
- /* Do nothing - conditional FALSE */
- } else if (ssi->nest >= (int) NELEMS(ssi->incs) - 1) {
- _shttpd_elog(E_LOG, ssi->conn,
- "ssi: #include: maximum nested level reached");
- } else if (!get_path(ssi->conn,
- inc->buf + 13, inc->nbuf - 13, buf, sizeof(buf))) {
- _shttpd_elog(E_LOG, ssi->conn, "ssi: bad #include: [%.*s]",
- inc->nbuf, inc->buf);
- } else if ((fp = fopen(buf, "r")) == NULL) {
- _shttpd_elog(E_LOG, ssi->conn,
- "ssi: fopen(%s): %s", buf, strerror(errno));
- } else {
- ssi->nest++;
- ssi->incs[ssi->nest].fp = fp;
- ssi->incs[ssi->nest].nbuf = 0;
- ssi->incs[ssi->nest].cond = SSI_GO;
- }
-}
-
-static char *
-trim_spaces(struct ssi_inc *inc)
-{
- char *p = inc->buf + inc->nbuf - 2;
-
- /* Trim spaces from the right */
- *p-- = '\0';
- while (isspace(* (unsigned char *) p))
- *p-- = '\0';
-
- /* Shift pointer to the start of attributes */
- for (p = inc->buf; !isspace(* (unsigned char *) p); p++);
- while (*p && isspace(* (unsigned char *) p)) p++;
-
- return (p);
-}
-
-static void
-do_if(struct ssi *ssi)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- char *name = trim_spaces(inc);
-
- inc->cond = evaluate(ssi, name) ? SSI_GO : SSI_STOP;
-}
-
-static void
-do_elif(struct ssi *ssi)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- char *name = trim_spaces(inc);
-
- if (inc->cond == SSI_STOP && evaluate(ssi, name))
- inc->cond = SSI_GO;
- else
- inc->cond = SSI_STOP;
-}
-static void
-do_endif(struct ssi *ssi)
-{
- ssi->incs[ssi->nest].cond = SSI_GO;
-}
-
-static void
-do_else(struct ssi *ssi)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
-
- inc->cond = inc->cond == SSI_GO ? SSI_STOP : SSI_GO;
-}
-
-static void
-do_call2(struct ssi *ssi, char *buf, int len, int *n)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- struct shttpd_arg arg;
-
- call(ssi, inc->buf, &arg, buf, len);
- (*n) += arg.out.num_bytes;
- if (arg.flags & SHTTPD_END_OF_OUTPUT)
- inc->state = SSI_PASS;
-}
-
-static void
-do_call(struct ssi *ssi, char *buf, int len, int *n)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- char *name = trim_spaces(inc);
-
- if (inc->cond == SSI_GO) {
- (void) memmove(inc->buf, name, strlen(name) + 1);
- inc->state = SSI_CALL;
- do_call2(ssi, buf, len, n);
- }
-}
-
-static void
-do_exec2(struct ssi *ssi, char *buf, int len, int *n)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- int i, ch;
-
- for (i = 0; i < len; i++) {
- if ((ch = fgetc(inc->pipe)) == EOF) {
- inc->state = SSI_PASS;
- (void) pclose(inc->pipe);
- inc->pipe = NULL;
- break;
- }
- *buf++ = ch;
- (*n)++;
- }
-}
-
-static void
-do_exec(struct ssi *ssi, char *buf, int len, int *n)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- char cmd[sizeof(inc->buf)], *e, *p;
-
- p = trim_spaces(inc);
-
- if (inc->cond == SSI_STOP) {
- /* Do nothing - conditional FALSE */
- } else if (*p != '"' || (e = strchr(p + 1, '"')) == NULL) {
- _shttpd_elog(E_LOG, ssi->conn, "ssi: bad exec(%s)", p);
- } else if (!_shttpd_url_decode(p + 1, e - p - 1, cmd, sizeof(cmd))) {
- _shttpd_elog(E_LOG, ssi->conn,
- "ssi: cannot url_decode: exec(%s)", p);
- } else if ((inc->pipe = popen(cmd, "r")) == NULL) {
- _shttpd_elog(E_LOG, ssi->conn, "ssi: popen(%s)", cmd);
- } else {
- inc->state = SSI_EXEC;
- do_exec2(ssi, buf, len, n);
- }
-}
-
-static const struct ssi_cmd {
- struct vec vec;
- void (*func)();
-} known_ssi_commands [] = {
- {{"include ", 8}, do_include },
- {{"if ", 3}, do_if },
- {{"elif ", 5}, do_elif },
- {{"else", 4}, do_else },
- {{"endif", 5}, do_endif },
- {{"call ", 5}, do_call },
- {{"exec ", 5}, do_exec },
- {{NULL, 0}, NULL }
-};
-
-static void
-do_command(struct ssi *ssi, char *buf, size_t len, int *n)
-{
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- const struct ssi_cmd *cmd;
-
- assert(len > 0);
- assert(inc->nbuf <= len);
- inc->state = SSI_PASS;
-
- for (cmd = known_ssi_commands; cmd->func != NULL; cmd++)
- if (inc->nbuf > (size_t) st.len + cmd->vec.len &&
- !memcmp(inc->buf + st.len, cmd->vec.ptr, cmd->vec.len)) {
- cmd->func(ssi, buf, len, n);
- break;
- }
-
- if (cmd->func == NULL)
- pass(inc, buf, n);
-
- inc->nbuf = 0;
-}
-
-static int
-read_ssi(struct stream *stream, void *vbuf, size_t len)
-{
- struct ssi *ssi = stream->conn->ssi;
- struct ssi_inc *inc = ssi->incs + ssi->nest;
- char *buf = vbuf;
- int ch = EOF, n = 0;
-
-again:
-
- if (inc->state == SSI_CALL)
- do_call2(ssi, buf, len, &n);
- else if (inc->state == SSI_EXEC)
- do_exec2(ssi, buf, len, &n);
-
- while (n + inc->nbuf < len && (ch = fgetc(inc->fp)) != EOF)
-
- switch (inc->state) {
-
- case SSI_PASS:
- if (ch == '<') {
- inc->nbuf = 0;
- inc->buf[inc->nbuf++] = ch;
- inc->state = SSI_BUF;
- } else if (inc->cond == SSI_GO) {
- buf[n++] = ch;
- }
- break;
-
- /*
- * We are buffering whole SSI command, until closing "-->".
- * That means that when do_command() is called, we can rely
- * on that full command with arguments is buffered in and
- * there is no need for streaming.
- * Restrictions:
- * 1. The command must fit in CMDBUFSIZ
- * 2. HTML comments inside the command ? Not sure about this.
- */
- case SSI_BUF:
- if (inc->nbuf >= sizeof(inc->buf) - 1) {
- pass(inc, buf + n, &n);
- } else if (ch == '>' &&
- !memcmp(inc->buf + inc->nbuf - 2, "--", 2)) {
- do_command(ssi, buf + n, len - n, &n);
- inc = ssi->incs + ssi->nest;
- } else {
- inc->buf[inc->nbuf++] = ch;
-
- /* If not SSI tag, pass it */
- if (inc->nbuf <= (size_t) st.len &&
- memcmp(inc->buf, st.ptr, inc->nbuf) != 0)
- pass(inc, buf + n, &n);
- }
- break;
-
- case SSI_EXEC:
- case SSI_CALL:
- break;
-
- default:
- /* Never happens */
- abort();
- break;
- }
-
- if (ssi->nest > 0 && n + inc->nbuf < len && ch == EOF) {
- (void) fclose(inc->fp);
- inc->fp = NULL;
- ssi->nest--;
- inc--;
- goto again;
- }
-
- return (n);
-}
-
-static void
-close_ssi(struct stream *stream)
-{
- struct ssi *ssi = stream->conn->ssi;
- size_t i;
-
- for (i = 0; i < NELEMS(ssi->incs); i++) {
- if (ssi->incs[i].fp != NULL)
- (void) fclose(ssi->incs[i].fp);
- if (ssi->incs[i].pipe != NULL)
- (void) pclose(ssi->incs[i].pipe);
- }
-
- free(ssi);
-}
-
-void
-_shttpd_do_ssi(struct conn *c)
-{
- char date[64];
- struct ssi *ssi;
-
- (void) strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT",
- localtime(&_shttpd_current_time));
-
- c->loc.io.head = c->loc.headers_len = _shttpd_snprintf(c->loc.io.buf,
- c->loc.io.size,
- "HTTP/1.1 200 OK\r\n"
- "Date: %s\r\n"
- "Content-Type: text/html\r\n"
- "Connection: close\r\n\r\n",
- date);
-
- c->status = 200;
- c->loc.io_class = &_shttpd_io_ssi;
- c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
-
- if (c->method == METHOD_HEAD) {
- _shttpd_stop_stream(&c->loc);
- } else if ((ssi = calloc(1, sizeof(struct ssi))) == NULL) {
- _shttpd_send_server_error(c, 500,
- "Cannot allocate SSI descriptor");
- } else {
- ssi->incs[0].fp = fdopen(c->loc.chan.fd, "r");
- ssi->conn = c;
- c->ssi = ssi;
- }
-}
-
-const struct io_class _shttpd_io_ssi = {
- "ssi",
- read_ssi,
- NULL,
- close_ssi
-};
-
-#endif /* !NO_SSI */
diff --git a/vendor/shttpd/io_ssl.c b/vendor/shttpd/io_ssl.c
deleted file mode 100644
index 6de0db2..0000000
--- a/vendor/shttpd/io_ssl.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-#if !defined(NO_SSL)
-struct ssl_func ssl_sw[] = {
- {"SSL_free", {0}},
- {"SSL_accept", {0}},
- {"SSL_connect", {0}},
- {"SSL_read", {0}},
- {"SSL_write", {0}},
- {"SSL_get_error", {0}},
- {"SSL_set_fd", {0}},
- {"SSL_new", {0}},
- {"SSL_CTX_new", {0}},
- {"SSLv23_server_method", {0}},
- {"SSL_library_init", {0}},
- {"SSL_CTX_use_PrivateKey_file", {0}},
- {"SSL_CTX_use_certificate_file",{0}},
- {NULL, {0}}
-};
-
-void
-_shttpd_ssl_handshake(struct stream *stream)
-{
- int n;
-
- if ((n = SSL_accept(stream->chan.ssl.ssl)) == 1) {
- DBG(("handshake: SSL accepted"));
- stream->flags |= FLAG_SSL_ACCEPTED;
- } else {
- n = SSL_get_error(stream->chan.ssl.ssl, n);
- if (n != SSL_ERROR_WANT_READ && n != SSL_ERROR_WANT_WRITE)
- stream->flags |= FLAG_CLOSED;
- DBG(("SSL_accept error %d", n));
- }
-}
-
-static int
-read_ssl(struct stream *stream, void *buf, size_t len)
-{
- int nread = -1;
-
- assert(stream->chan.ssl.ssl != NULL);
-
- if (!(stream->flags & FLAG_SSL_ACCEPTED))
- _shttpd_ssl_handshake(stream);
-
- if (stream->flags & FLAG_SSL_ACCEPTED)
- nread = SSL_read(stream->chan.ssl.ssl, buf, len);
-
- return (nread);
-}
-
-static int
-write_ssl(struct stream *stream, const void *buf, size_t len)
-{
- assert(stream->chan.ssl.ssl != NULL);
- return (SSL_write(stream->chan.ssl.ssl, buf, len));
-}
-
-static void
-close_ssl(struct stream *stream)
-{
- assert(stream->chan.ssl.sock != -1);
- assert(stream->chan.ssl.ssl != NULL);
- (void) closesocket(stream->chan.ssl.sock);
- SSL_free(stream->chan.ssl.ssl);
-}
-
-const struct io_class _shttpd_io_ssl = {
- "ssl",
- read_ssl,
- write_ssl,
- close_ssl
-};
-#endif /* !NO_SSL */
diff --git a/vendor/shttpd/llist.h b/vendor/shttpd/llist.h
deleted file mode 100644
index 04e79bb..0000000
--- a/vendor/shttpd/llist.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#ifndef LLIST_HEADER_INCLUDED
-#define LLIST_HEADER_INCLUDED
-
-/*
- * Linked list macros.
- */
-struct llhead {
- struct llhead *prev;
- struct llhead *next;
-};
-
-#define LL_INIT(N) ((N)->next = (N)->prev = (N))
-
-#define LL_HEAD(H) struct llhead H = { &H, &H }
-
-#define LL_ENTRY(P,T,N) ((T *)((char *)(P) - offsetof(T, N)))
-
-#define LL_ADD(H, N) \
- do { \
- ((H)->next)->prev = (N); \
- (N)->next = ((H)->next); \
- (N)->prev = (H); \
- (H)->next = (N); \
- } while (0)
-
-#define LL_TAIL(H, N) \
- do { \
- ((H)->prev)->next = (N); \
- (N)->prev = ((H)->prev); \
- (N)->next = (H); \
- (H)->prev = (N); \
- } while (0)
-
-#define LL_DEL(N) \
- do { \
- ((N)->next)->prev = ((N)->prev); \
- ((N)->prev)->next = ((N)->next); \
- LL_INIT(N); \
- } while (0)
-
-#define LL_EMPTY(N) ((N)->next == (N))
-
-#define LL_FOREACH(H,N) for (N = (H)->next; N != (H); N = (N)->next)
-
-#define LL_FOREACH_SAFE(H,N,T) \
- for (N = (H)->next, T = (N)->next; N != (H); \
- N = (T), T = (N)->next)
-
-#endif /* LLIST_HEADER_INCLUDED */
diff --git a/vendor/shttpd/log.c b/vendor/shttpd/log.c
deleted file mode 100644
index 8c506f4..0000000
--- a/vendor/shttpd/log.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-/*
- * Log function
- */
-void
-_shttpd_elog(int flags, struct conn *c, const char *fmt, ...)
-{
- char date[64], buf[URI_MAX];
- int len;
- FILE *fp = c == NULL ? NULL : c->ctx->error_log;
- va_list ap;
-
- /* Print to stderr */
- if (c == NULL || !IS_TRUE(c->ctx, OPT_INETD)) {
- va_start(ap, fmt);
- (void) vfprintf(stderr, fmt, ap);
- (void) fputc('\n', stderr);
- va_end(ap);
- }
-
- strftime(date, sizeof(date), "%a %b %d %H:%M:%S %Y",
- localtime(&_shttpd_current_time));
-
- len = _shttpd_snprintf(buf, sizeof(buf),
- "[%s] [error] [client %s] \"%s\" ",
- date, c ? inet_ntoa(c->sa.u.sin.sin_addr) : "-",
- c && c->request ? c->request : "-");
-
- va_start(ap, fmt);
- (void) vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
- va_end(ap);
-
- buf[sizeof(buf) - 1] = '\0';
-
- if (fp != NULL && (flags & (E_FATAL | E_LOG))) {
- (void) fprintf(fp, "%s\n", buf);
- (void) fflush(fp);
- }
-
- if (flags & E_FATAL)
- exit(EXIT_FAILURE);
-}
-
-void
-_shttpd_log_access(FILE *fp, const struct conn *c)
-{
- static const struct vec dash = {"-", 1};
-
- const struct vec *user = &c->ch.user.v_vec;
- const struct vec *referer = &c->ch.referer.v_vec;
- const struct vec *user_agent = &c->ch.useragent.v_vec;
- char date[64], buf[URI_MAX], *q1 = "\"", *q2 = "\"";
-
- if (user->len == 0)
- user = ‐
-
- if (referer->len == 0) {
- referer = ‐
- q1 = "";
- }
-
- if (user_agent->len == 0) {
- user_agent = ‐
- q2 = "";
- }
-
- (void) strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S",
- localtime(&c->birth_time));
-
- (void) _shttpd_snprintf(buf, sizeof(buf),
- "%s - %.*s [%s %+05d] \"%s\" %d %lu %s%.*s%s %s%.*s%s",
- inet_ntoa(c->sa.u.sin.sin_addr), user->len, user->ptr,
- date, _shttpd_tz_offset, c->request ? c->request : "-",
- c->status, (unsigned long) c->loc.io.total,
- q1, referer->len, referer->ptr, q1,
- q2, user_agent->len, user_agent->ptr, q2);
-
- if (fp != NULL) {
- (void) fprintf(fp, "%s\n", buf);
- (void) fflush(fp);
- }
-}
diff --git a/vendor/shttpd/md5.c b/vendor/shttpd/md5.c
deleted file mode 100644
index ddd90e1..0000000
--- a/vendor/shttpd/md5.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest. This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-#include "defs.h"
-
-#ifndef HAVE_MD5
-#if __BYTE_ORDER == 1234
-#define byteReverse(buf, len) /* Nothing */
-#else
-/*
- * Note: this code is harmless on little-endian machines.
- */
-static void byteReverse(unsigned char *buf, unsigned longs)
-{
- uint32_t t;
- do {
- t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
- ((unsigned) buf[1] << 8 | buf[0]);
- *(uint32_t *) buf = t;
- buf += 4;
- } while (--longs);
-}
-#endif /* __BYTE_ORDER */
-
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
-( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
-
-/*
- * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-void MD5Init(MD5_CTX *ctx)
-{
- ctx->buf[0] = 0x67452301;
- ctx->buf[1] = 0xefcdab89;
- ctx->buf[2] = 0x98badcfe;
- ctx->buf[3] = 0x10325476;
-
- ctx->bits[0] = 0;
- ctx->bits[1] = 0;
-}
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data. MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
-{
- register uint32_t a, b, c, d;
-
- a = buf[0];
- b = buf[1];
- c = buf[2];
- d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-void
-MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
-{
- uint32_t t;
-
- /* Update bitcount */
-
- t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
- ctx->bits[1]++; /* Carry from low to high */
- ctx->bits[1] += len >> 29;
-
- t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
-
- /* Handle any leading odd-sized chunks */
-
- if (t) {
- unsigned char *p = (unsigned char *) ctx->in + t;
-
- t = 64 - t;
- if (len < t) {
- memcpy(p, buf, len);
- return;
- }
- memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- buf += t;
- len -= t;
- }
- /* Process data in 64-byte chunks */
-
- while (len >= 64) {
- memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- buf += 64;
- len -= 64;
- }
-
- /* Handle any remaining bytes of data. */
-
- memcpy(ctx->in, buf, len);
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-void
-MD5Final(unsigned char digest[16], MD5_CTX *ctx)
-{
- unsigned count;
- unsigned char *p;
-
- /* Compute number of bytes mod 64 */
- count = (ctx->bits[0] >> 3) & 0x3F;
-
- /* Set the first char of padding to 0x80. This is safe since there is
- always at least one byte free */
- p = ctx->in + count;
- *p++ = 0x80;
-
- /* Bytes of padding needed to make 64 bytes */
- count = 64 - 1 - count;
-
- /* Pad out to 56 mod 64 */
- if (count < 8) {
- /* Two lots of padding: Pad the first block to 64 bytes */
- memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-
- /* Now fill the next block with 56 bytes */
- memset(ctx->in, 0, 56);
- } else {
- /* Pad block to 56 bytes */
- memset(p, 0, count - 8);
- }
- byteReverse(ctx->in, 14);
-
- /* Append length in bits and transform */
- ((uint32_t *) ctx->in)[14] = ctx->bits[0];
- ((uint32_t *) ctx->in)[15] = ctx->bits[1];
-
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- byteReverse((unsigned char *) ctx->buf, 4);
- memcpy(digest, ctx->buf, 16);
- memset((char *) ctx, 0, sizeof(ctx)); /* In case it's sensitive */
-}
-
-#endif /* !HAVE_MD5 */
diff --git a/vendor/shttpd/md5.h b/vendor/shttpd/md5.h
deleted file mode 100644
index fcca00e..0000000
--- a/vendor/shttpd/md5.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#ifndef MD5_HEADER_INCLUDED
-#define MD5_HEADER_INCLUDED
-
-typedef struct MD5Context {
- uint32_t buf[4];
- uint32_t bits[2];
- unsigned char in[64];
-} MD5_CTX;
-
-extern void MD5Init(MD5_CTX *ctx);
-extern void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len);
-extern void MD5Final(unsigned char digest[16], MD5_CTX *ctx);
-
-#endif /*MD5_HEADER_INCLUDED */
diff --git a/vendor/shttpd/shttpd.c b/vendor/shttpd/shttpd.c
deleted file mode 100644
index 8b66243..0000000
--- a/vendor/shttpd/shttpd.c
+++ /dev/null
@@ -1,1903 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-/*
- * Small and portable HTTP server, http://shttpd.sourceforge.net
- * $Id: shttpd.c,v 1.57 2008/08/23 21:00:38 drozd Exp $
- */
-
-#include "defs.h"
-
-time_t _shttpd_current_time; /* Current UTC time */
-int _shttpd_tz_offset; /* Time zone offset from UTC */
-int _shttpd_exit_flag; /* Program exit flag */
-
-const struct vec _shttpd_known_http_methods[] = {
- {"GET", 3},
- {"POST", 4},
- {"PUT", 3},
- {"DELETE", 6},
- {"HEAD", 4},
- {NULL, 0}
-};
-
-/*
- * This structure tells how HTTP headers must be parsed.
- * Used by parse_headers() function.
- */
-#define OFFSET(x) offsetof(struct headers, x)
-static const struct http_header http_headers[] = {
- {16, HDR_INT, OFFSET(cl), "Content-Length: " },
- {14, HDR_STRING, OFFSET(ct), "Content-Type: " },
- {12, HDR_STRING, OFFSET(useragent), "User-Agent: " },
- {19, HDR_DATE, OFFSET(ims), "If-Modified-Since: " },
- {15, HDR_STRING, OFFSET(auth), "Authorization: " },
- {9, HDR_STRING, OFFSET(referer), "Referer: " },
- {8, HDR_STRING, OFFSET(cookie), "Cookie: " },
- {10, HDR_STRING, OFFSET(location), "Location: " },
- {8, HDR_INT, OFFSET(status), "Status: " },
- {7, HDR_STRING, OFFSET(range), "Range: " },
- {12, HDR_STRING, OFFSET(connection), "Connection: " },
- {19, HDR_STRING, OFFSET(transenc), "Transfer-Encoding: " },
- {0, HDR_INT, 0, NULL }
-};
-
-struct shttpd_ctx *init_ctx(const char *config_file, int argc, char *argv[]);
-static void process_connection(struct conn *, int, int);
-
-int
-_shttpd_is_true(const char *str)
-{
- static const char *trues[] = {"1", "yes", "true", "jawohl", NULL};
- const char **p;
-
- for (p = trues; *p != NULL; p++)
- if (str && !strcmp(str, *p))
- return (TRUE);
-
- return (FALSE);
-}
-
-static void
-free_list(struct llhead *head, void (*dtor)(struct llhead *))
-{
- struct llhead *lp, *tmp;
-
- LL_FOREACH_SAFE(head, lp, tmp) {
- LL_DEL(lp);
- dtor(lp);
- }
-}
-
-static void
-listener_destructor(struct llhead *lp)
-{
- struct listener *listener = LL_ENTRY(lp, struct listener, link);
-
- (void) closesocket(listener->sock);
- free(listener);
-}
-
-static void
-registered_uri_destructor(struct llhead *lp)
-{
- struct registered_uri *ruri = LL_ENTRY(lp, struct registered_uri, link);
-
- free((void *) ruri->uri);
- free(ruri);
-}
-
-static void
-acl_destructor(struct llhead *lp)
-{
- struct acl *acl = LL_ENTRY(lp, struct acl, link);
- free(acl);
-}
-
-int
-_shttpd_url_decode(const char *src, int src_len, char *dst, int dst_len)
-{
- int i, j, a, b;
-#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
-
- for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++)
- switch (src[i]) {
- case '%':
- if (isxdigit(((unsigned char *) src)[i + 1]) &&
- isxdigit(((unsigned char *) src)[i + 2])) {
- a = tolower(((unsigned char *)src)[i + 1]);
- b = tolower(((unsigned char *)src)[i + 2]);
- dst[j] = (HEXTOI(a) << 4) | HEXTOI(b);
- i += 2;
- } else {
- dst[j] = '%';
- }
- break;
- default:
- dst[j] = src[i];
- break;
- }
-
- dst[j] = '\0'; /* Null-terminate the destination */
-
- return (j);
-}
-
-static const char *
-is_alias(struct shttpd_ctx *ctx, const char *uri,
- struct vec *a_uri, struct vec *a_path)
-{
- const char *p, *s = ctx->options[OPT_ALIASES];
- size_t len;
-
- DBG(("is_alias: aliases [%s]", s == NULL ? "" : s));
-
- FOR_EACH_WORD_IN_LIST(s, len) {
-
- if ((p = memchr(s, '=', len)) == NULL || p >= s + len || p == s)
- continue;
-
- if (memcmp(uri, s, p - s) == 0) {
- a_uri->ptr = s;
- a_uri->len = p - s;
- a_path->ptr = ++p;
- a_path->len = (s + len) - p;
- return (s);
- }
- }
-
- return (NULL);
-}
-
-void
-_shttpd_stop_stream(struct stream *stream)
-{
- if (stream->io_class != NULL && stream->io_class->close != NULL)
- stream->io_class->close(stream);
-
- stream->io_class= NULL;
- stream->flags |= FLAG_CLOSED;
- stream->flags &= ~(FLAG_R | FLAG_W | FLAG_ALWAYS_READY);
-
- DBG(("%d %s stopped. %lu of content data, %d now in a buffer",
- stream->conn->rem.chan.sock,
- stream->io_class ? stream->io_class->name : "(null)",
- (unsigned long) stream->io.total, (int) io_data_len(&stream->io)));
-}
-
-/*
- * Setup listening socket on given port, return socket
- */
-static int
-shttpd_open_listening_port(int port)
-{
- int sock, on = 1;
- struct usa sa;
-
-#ifdef _WIN32
- {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);}
-#endif /* _WIN32 */
-
- sa.len = sizeof(sa.u.sin);
- sa.u.sin.sin_family = AF_INET;
- sa.u.sin.sin_port = htons((uint16_t) port);
- sa.u.sin.sin_addr.s_addr = htonl(INADDR_ANY);
-
- if ((sock = socket(PF_INET, SOCK_STREAM, 6)) == -1)
- goto fail;
- if (_shttpd_set_non_blocking_mode(sock) != 0)
- goto fail;
- if (setsockopt(sock, SOL_SOCKET,
- SO_REUSEADDR,(char *) &on, sizeof(on)) != 0)
- goto fail;
- if (bind(sock, &sa.u.sa, sa.len) < 0)
- goto fail;
- if (listen(sock, 128) != 0)
- goto fail;
-
-#ifndef _WIN32
- (void) fcntl(sock, F_SETFD, FD_CLOEXEC);
-#endif /* !_WIN32 */
-
- return (sock);
-fail:
- if (sock != -1)
- (void) closesocket(sock);
- _shttpd_elog(E_LOG, NULL, "open_listening_port(%d): %s", port, strerror(errno));
- return (-1);
-}
-
-/*
- * Check whether full request is buffered Return headers length, or 0
- */
-int
-_shttpd_get_headers_len(const char *buf, size_t buflen)
-{
- const char *s, *e;
- int len = 0;
-
- for (s = buf, e = s + buflen - 1; len == 0 && s < e; s++)
- /* Control characters are not allowed but >=128 is. */
- if (!isprint(* (unsigned char *) s) && *s != '\r' &&
- *s != '\n' && * (unsigned char *) s < 128)
- len = -1;
- else if (s[0] == '\n' && s[1] == '\n')
- len = s - buf + 2;
- else if (s[0] == '\n' && &s[1] < e &&
- s[1] == '\r' && s[2] == '\n')
- len = s - buf + 3;
-
- return (len);
-}
-
-/*
- * Send error message back to a client.
- */
-void
-_shttpd_send_server_error(struct conn *c, int status, const char *reason)
-{
- struct llhead *lp;
- struct error_handler *e;
-
- LL_FOREACH(&c->ctx->error_handlers, lp) {
- e = LL_ENTRY(lp, struct error_handler, link);
-
- if (e->code == status) {
- if (c->loc.io_class != NULL &&
- c->loc.io_class->close != NULL)
- c->loc.io_class->close(&c->loc);
- io_clear(&c->loc.io);
- _shttpd_setup_embedded_stream(c,
- e->callback, e->callback_data);
- return;
- }
- }
-
- io_clear(&c->loc.io);
- c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
- "HTTP/1.1 %d %s\r\n"
- "Content-Type: text/plain\r\n"
- "Content-Length: 12\r\n"
- "\r\n"
- "Error: %03d\r\n",
- status, reason, status);
- c->loc.content_len = 10;
- c->status = status;
- _shttpd_stop_stream(&c->loc);
-}
-
-/*
- * Convert month to the month number. Return -1 on error, or month number
- */
-static int
-montoi(const char *s)
-{
- static const char *ar[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
- size_t i;
-
- for (i = 0; i < sizeof(ar) / sizeof(ar[0]); i++)
- if (!strcmp(s, ar[i]))
- return (i);
-
- return (-1);
-}
-
-/*
- * Parse date-time string, and return the corresponding time_t value
- */
-static time_t
-date_to_epoch(const char *s)
-{
- struct tm tm, *tmp;
- char mon[32];
- int sec, min, hour, mday, month, year;
-
- (void) memset(&tm, 0, sizeof(tm));
- sec = min = hour = mday = month = year = 0;
-
- if (((sscanf(s, "%d/%3s/%d %d:%d:%d",
- &mday, mon, &year, &hour, &min, &sec) == 6) ||
- (sscanf(s, "%d %3s %d %d:%d:%d",
- &mday, mon, &year, &hour, &min, &sec) == 6) ||
- (sscanf(s, "%*3s, %d %3s %d %d:%d:%d",
- &mday, mon, &year, &hour, &min, &sec) == 6) ||
- (sscanf(s, "%d-%3s-%d %d:%d:%d",
- &mday, mon, &year, &hour, &min, &sec) == 6)) &&
- (month = montoi(mon)) != -1) {
- tm.tm_mday = mday;
- tm.tm_mon = month;
- tm.tm_year = year;
- tm.tm_hour = hour;
- tm.tm_min = min;
- tm.tm_sec = sec;
- }
-
- if (tm.tm_year > 1900)
- tm.tm_year -= 1900;
- else if (tm.tm_year < 70)
- tm.tm_year += 100;
-
- /* Set Daylight Saving Time field */
- tmp = localtime(&_shttpd_current_time);
- tm.tm_isdst = tmp->tm_isdst;
-
- return (mktime(&tm));
-}
-
-static void
-remove_double_dots(char *s)
-{
- char *p = s;
-
- while (*s != '\0') {
- *p++ = *s++;
- if (s[-1] == '/' || s[-1] == '\\')
- while (*s == '.' || *s == '/' || *s == '\\')
- s++;
- }
- *p = '\0';
-}
-
-void
-_shttpd_parse_headers(const char *s, int len, struct headers *parsed)
-{
- const struct http_header *h;
- union variant *v;
- const char *p, *e = s + len;
-
- DBG(("parsing headers (len %d): [%.*s]", len, len, s));
-
- /* Loop through all headers in the request */
- while (s < e) {
-
- /* Find where this header ends */
- for (p = s; p < e && *p != '\n'; ) p++;
-
- /* Is this header known to us ? */
- for (h = http_headers; h->len != 0; h++)
- if (e - s > h->len &&
- !_shttpd_strncasecmp(s, h->name, h->len))
- break;
-
- /* If the header is known to us, store its value */
- if (h->len != 0) {
-
- /* Shift to where value starts */
- s += h->len;
-
- /* Find place to store the value */
- v = (union variant *) ((char *) parsed + h->offset);
-
- /* Fetch header value into the connection structure */
- if (h->type == HDR_STRING) {
- v->v_vec.ptr = s;
- v->v_vec.len = p - s;
- if (p[-1] == '\r' && v->v_vec.len > 0)
- v->v_vec.len--;
- } else if (h->type == HDR_INT) {
- v->v_big_int = strtoul(s, NULL, 10);
- } else if (h->type == HDR_DATE) {
- v->v_time = date_to_epoch(s);
- }
- }
-
- s = p + 1; /* Shift to the next header */
- }
-}
-
-static const struct {
- const char *extension;
- int ext_len;
- const char *mime_type;
-} builtin_mime_types[] = {
- {"html", 4, "text/html" },
- {"htm", 3, "text/html" },
- {"txt", 3, "text/plain" },
- {"css", 3, "text/css" },
- {"ico", 3, "image/x-icon" },
- {"gif", 3, "image/gif" },
- {"jpg", 3, "image/jpeg" },
- {"jpeg", 4, "image/jpeg" },
- {"png", 3, "image/png" },
- {"svg", 3, "image/svg+xml" },
- {"torrent", 7, "application/x-bittorrent" },
- {"wav", 3, "audio/x-wav" },
- {"mp3", 3, "audio/x-mp3" },
- {"mid", 3, "audio/mid" },
- {"m3u", 3, "audio/x-mpegurl" },
- {"ram", 3, "audio/x-pn-realaudio" },
- {"ra", 2, "audio/x-pn-realaudio" },
- {"doc", 3, "application/msword", },
- {"exe", 3, "application/octet-stream" },
- {"zip", 3, "application/x-zip-compressed" },
- {"xls", 3, "application/excel" },
- {"tgz", 3, "application/x-tar-gz" },
- {"tar.gz", 6, "application/x-tar-gz" },
- {"tar", 3, "application/x-tar" },
- {"gz", 2, "application/x-gunzip" },
- {"arj", 3, "application/x-arj-compressed" },
- {"rar", 3, "application/x-arj-compressed" },
- {"rtf", 3, "application/rtf" },
- {"pdf", 3, "application/pdf" },
- {"swf", 3, "application/x-shockwave-flash" },
- {"mpg", 3, "video/mpeg" },
- {"mpeg", 4, "video/mpeg" },
- {"asf", 3, "video/x-ms-asf" },
- {"avi", 3, "video/x-msvideo" },
- {"bmp", 3, "image/bmp" },
- {NULL, 0, NULL }
-};
-
-void
-_shttpd_get_mime_type(struct shttpd_ctx *ctx,
- const char *uri, int len, struct vec *vec)
-{
- const char *eq, *p = ctx->options[OPT_MIME_TYPES];
- int i, n, ext_len;
-
- /* Firt, loop through the custom mime types if any */
- FOR_EACH_WORD_IN_LIST(p, n) {
- if ((eq = memchr(p, '=', n)) == NULL || eq >= p + n || eq == p)
- continue;
- ext_len = eq - p;
- if (len > ext_len && uri[len - ext_len - 1] == '.' &&
- !_shttpd_strncasecmp(p, &uri[len - ext_len], ext_len)) {
- vec->ptr = eq + 1;
- vec->len = p + n - vec->ptr;
- return;
- }
- }
-
- /* If no luck, try built-in mime types */
- for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
- ext_len = builtin_mime_types[i].ext_len;
- if (len > ext_len && uri[len - ext_len - 1] == '.' &&
- !_shttpd_strncasecmp(builtin_mime_types[i].extension,
- &uri[len - ext_len], ext_len)) {
- vec->ptr = builtin_mime_types[i].mime_type;
- vec->len = strlen(vec->ptr);
- return;
- }
- }
-
- /* Oops. This extension is unknown to us. Fallback to text/plain */
- vec->ptr = "text/plain";
- vec->len = strlen(vec->ptr);
-}
-
-/*
- * For given directory path, substitute it to valid index file.
- * Return 0 if index file has been found, -1 if not found
- */
-static int
-find_index_file(struct conn *c, char *path, size_t maxpath, struct stat *stp)
-{
- char buf[FILENAME_MAX];
- const char *s = c->ctx->options[OPT_INDEX_FILES];
- size_t len;
-
- FOR_EACH_WORD_IN_LIST(s, len) {
- /* path must end with '/' character */
- _shttpd_snprintf(buf, sizeof(buf), "%s%.*s", path, len, s);
- if (_shttpd_stat(buf, stp) == 0) {
- _shttpd_strlcpy(path, buf, maxpath);
- _shttpd_get_mime_type(c->ctx, s, len, &c->mime_type);
- return (0);
- }
- }
-
- return (-1);
-}
-
-/*
- * Try to open requested file, return 0 if OK, -1 if error.
- * If the file is given arguments using PATH_INFO mechanism,
- * initialize pathinfo pointer.
- */
-static int
-get_path_info(struct conn *c, char *path, struct stat *stp)
-{
- char *p, *e;
-
- if (_shttpd_stat(path, stp) == 0)
- return (0);
-
- p = path + strlen(path);
- e = path + strlen(c->ctx->options[OPT_ROOT]) + 2;
-
- /* Strip directory parts of the path one by one */
- for (; p > e; p--)
- if (*p == '/') {
- *p = '\0';
- if (!_shttpd_stat(path, stp) && !S_ISDIR(stp->st_mode)) {
- c->path_info = p + 1;
- return (0);
- } else {
- *p = '/';
- }
- }
-
- return (-1);
-}
-
-static void
-decide_what_to_do(struct conn *c)
-{
- char path[URI_MAX], buf[1024], *root;
- struct vec alias_uri, alias_path;
- struct stat st;
- int rc;
- struct registered_uri *ruri;
-
- DBG(("decide_what_to_do: [%s]", c->uri));
-
- if ((c->query = strchr(c->uri, '?')) != NULL)
- *c->query++ = '\0';
-
- _shttpd_url_decode(c->uri, strlen(c->uri), c->uri, strlen(c->uri) + 1);
- remove_double_dots(c->uri);
-
- root = c->ctx->options[OPT_ROOT];
- if (strlen(c->uri) + strlen(root) >= sizeof(path)) {
- _shttpd_send_server_error(c, 400, "URI is too long");
- return;
- }
-
- (void) _shttpd_snprintf(path, sizeof(path), "%s%s", root, c->uri);
-
- /* User may use the aliases - check URI for mount point */
- if (is_alias(c->ctx, c->uri, &alias_uri, &alias_path) != NULL) {
- (void) _shttpd_snprintf(path, sizeof(path), "%.*s%s",
- alias_path.len, alias_path.ptr, c->uri + alias_uri.len);
- DBG(("using alias %.*s -> %.*s", alias_uri.len, alias_uri.ptr,
- alias_path.len, alias_path.ptr));
- }
-
-#if !defined(NO_AUTH)
- if (_shttpd_check_authorization(c, path) != 1) {
- _shttpd_send_authorization_request(c);
- } else
-#endif /* NO_AUTH */
- if ((ruri = _shttpd_is_registered_uri(c->ctx, c->uri)) != NULL) {
- _shttpd_setup_embedded_stream(c,
- ruri->callback, ruri->callback_data);
- } else
- if (strstr(path, HTPASSWD)) {
- /* Do not allow to view passwords files */
- _shttpd_send_server_error(c, 403, "Forbidden");
- } else
-#if !defined(NO_AUTH)
- if ((c->method == METHOD_PUT || c->method == METHOD_DELETE) &&
- (c->ctx->options[OPT_AUTH_PUT] == NULL ||
- !_shttpd_is_authorized_for_put(c))) {
- _shttpd_send_authorization_request(c);
- } else
-#endif /* NO_AUTH */
- if (c->method == METHOD_PUT) {
- c->status = _shttpd_stat(path, &st) == 0 ? 200 : 201;
-
- if (c->ch.range.v_vec.len > 0) {
- _shttpd_send_server_error(c, 501,
- "PUT Range Not Implemented");
- } else if ((rc = _shttpd_put_dir(path)) == 0) {
- _shttpd_send_server_error(c, 200, "OK");
- } else if (rc == -1) {
- _shttpd_send_server_error(c, 500, "PUT Directory Error");
- } else if (c->rem.content_len == 0) {
- _shttpd_send_server_error(c, 411, "Length Required");
- } else if ((c->loc.chan.fd = _shttpd_open(path, O_WRONLY | O_BINARY |
- O_CREAT | O_NONBLOCK | O_TRUNC, 0644)) == -1) {
- _shttpd_send_server_error(c, 500, "PUT Error");
- } else {
- DBG(("PUT file [%s]", c->uri));
- c->loc.io_class = &_shttpd_io_file;
- c->loc.flags |= FLAG_W | FLAG_ALWAYS_READY ;
- }
- } else if (c->method == METHOD_DELETE) {
- DBG(("DELETE [%s]", c->uri));
- if (_shttpd_remove(path) == 0)
- _shttpd_send_server_error(c, 200, "OK");
- else
- _shttpd_send_server_error(c, 500, "DELETE Error");
- } else if (get_path_info(c, path, &st) != 0) {
- _shttpd_send_server_error(c, 404, "Not Found");
- } else if (S_ISDIR(st.st_mode) && path[strlen(path) - 1] != '/') {
- (void) _shttpd_snprintf(buf, sizeof(buf),
- "Moved Permanently\r\nLocation: %s/", c->uri);
- _shttpd_send_server_error(c, 301, buf);
- } else if (S_ISDIR(st.st_mode) &&
- find_index_file(c, path, sizeof(path) - 1, &st) == -1 &&
- !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
- _shttpd_send_server_error(c, 403, "Directory Listing Denied");
- } else if (S_ISDIR(st.st_mode) && IS_TRUE(c->ctx, OPT_DIR_LIST)) {
- if ((c->loc.chan.dir.path = _shttpd_strdup(path)) != NULL)
- _shttpd_get_dir(c);
- else
- _shttpd_send_server_error(c, 500, "GET Directory Error");
- } else if (S_ISDIR(st.st_mode) && !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
- _shttpd_send_server_error(c, 403, "Directory listing denied");
-#if !defined(NO_CGI)
- } else if (_shttpd_match_extension(path,
- c->ctx->options[OPT_CGI_EXTENSIONS])) {
- if (c->method != METHOD_POST && c->method != METHOD_GET) {
- _shttpd_send_server_error(c, 501, "Bad method ");
- } else if ((_shttpd_run_cgi(c, path)) == -1) {
- _shttpd_send_server_error(c, 500, "Cannot exec CGI");
- } else {
- _shttpd_do_cgi(c);
- }
-#endif /* NO_CGI */
-#if !defined(NO_SSI)
- } else if (_shttpd_match_extension(path,
- c->ctx->options[OPT_SSI_EXTENSIONS])) {
- if ((c->loc.chan.fd = _shttpd_open(path,
- O_RDONLY | O_BINARY, 0644)) == -1) {
- _shttpd_send_server_error(c, 500, "SSI open error");
- } else {
- _shttpd_do_ssi(c);
- }
-#endif /* NO_CGI */
- } else if (c->ch.ims.v_time && st.st_mtime <= c->ch.ims.v_time) {
- _shttpd_send_server_error(c, 304, "Not Modified");
- } else if ((c->loc.chan.fd = _shttpd_open(path,
- O_RDONLY | O_BINARY, 0644)) != -1) {
- _shttpd_get_file(c, &st);
- } else {
- _shttpd_send_server_error(c, 500, "Internal Error");
- }
-}
-
-static int
-set_request_method(struct conn *c)
-{
- const struct vec *v;
-
- /* Set the request method */
- for (v = _shttpd_known_http_methods; v->ptr != NULL; v++)
- if (!memcmp(c->rem.io.buf, v->ptr, v->len)) {
- c->method = v - _shttpd_known_http_methods;
- break;
- }
-
- return (v->ptr == NULL);
-}
-
-static void
-parse_http_request(struct conn *c)
-{
- char *s, *e, *p, *start;
- int uri_len, req_len, n;
-
- s = io_data(&c->rem.io);;
- req_len = c->rem.headers_len =
- _shttpd_get_headers_len(s, io_data_len(&c->rem.io));
-
- if (req_len == 0 && io_space_len(&c->rem.io) == 0) {
- io_clear(&c->rem.io);
- _shttpd_send_server_error(c, 400, "Request is too big");
- }
-
- if (req_len == 0) {
- return;
- } else if (req_len < 16) { /* Minimal: "GET / HTTP/1.0\n\n" */
- _shttpd_send_server_error(c, 400, "Bad request");
- } else if (set_request_method(c)) {
- _shttpd_send_server_error(c, 501, "Method Not Implemented");
- } else if ((c->request = _shttpd_strndup(s, req_len)) == NULL) {
- _shttpd_send_server_error(c, 500, "Cannot allocate request");
- }
-
- if (c->loc.flags & FLAG_CLOSED)
- return;
-
- io_inc_tail(&c->rem.io, req_len);
-
- DBG(("Conn %d: parsing request: [%.*s]", c->rem.chan.sock, req_len, s));
- c->rem.flags |= FLAG_HEADERS_PARSED;
-
- /* Set headers pointer. Headers follow the request line */
- c->headers = memchr(c->request, '\n', req_len);
- assert(c->headers != NULL);
- assert(c->headers < c->request + req_len);
- if (c->headers > c->request && c->headers[-1] == '\r')
- c->headers[-1] = '\0';
- *c->headers++ = '\0';
-
- /*
- * Now make a copy of the URI, because it will be URL-decoded,
- * and we need a copy of unmodified URI for the access log.
- * First, we skip the REQUEST_METHOD and shift to the URI.
- */
- for (p = c->request, e = p + req_len; *p != ' ' && p < e; p++);
- while (p < e && *p == ' ')
- p++;
-
- /* Now remember where URI starts, and shift to the end of URI */
- for (start = p; p < e && !isspace((unsigned char)*p); ) p++;
- uri_len = p - start;
-
- /* Skip space following the URI */
- while (p < e && *p == ' ')
- p++;
-
- /* Now comes the HTTP-Version in the form HTTP/<major>.<minor> */
- if (sscanf(p, "HTTP/%lu.%lu%n",
- &c->major_version, &c->minor_version, &n) != 2 || p[n] != '\0') {
- _shttpd_send_server_error(c, 400, "Bad HTTP version");
- } else if (c->major_version > 1 ||
- (c->major_version == 1 && c->minor_version > 1)) {
- _shttpd_send_server_error(c, 505, "HTTP version not supported");
- } else if (uri_len <= 0) {
- _shttpd_send_server_error(c, 400, "Bad URI");
- } else if ((c->uri = malloc(uri_len + 1)) == NULL) {
- _shttpd_send_server_error(c, 500, "Cannot allocate URI");
- } else {
- _shttpd_strlcpy(c->uri, (char *) start, uri_len + 1);
- _shttpd_parse_headers(c->headers,
- (c->request + req_len) - c->headers, &c->ch);
-
- /* Remove the length of request from total, count only data */
- assert(c->rem.io.total >= (big_int_t) req_len);
- c->rem.io.total -= req_len;
- c->rem.content_len = c->ch.cl.v_big_int;
- decide_what_to_do(c);
- }
-}
-
-static void
-add_socket(struct worker *worker, int sock, int is_ssl)
-{
- struct shttpd_ctx *ctx = worker->ctx;
- struct conn *c;
- struct usa sa;
- int l = IS_TRUE(ctx, OPT_INETD) ? E_FATAL : E_LOG;
-#if !defined(NO_SSL)
- SSL *ssl = NULL;
-#else
- is_ssl = is_ssl; /* supress warnings */
-#endif /* NO_SSL */
-
- sa.len = sizeof(sa.u.sin);
- (void) _shttpd_set_non_blocking_mode(sock);
-
- if (getpeername(sock, &sa.u.sa, &sa.len)) {
- _shttpd_elog(l, NULL, "add_socket: %s", strerror(errno));
-#if !defined(NO_SSL)
- } else if (is_ssl && (ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
- _shttpd_elog(l, NULL, "add_socket: SSL_new: %s", strerror(ERRNO));
- (void) closesocket(sock);
- } else if (is_ssl && SSL_set_fd(ssl, sock) == 0) {
- _shttpd_elog(l, NULL, "add_socket: SSL_set_fd: %s", strerror(ERRNO));
- (void) closesocket(sock);
- SSL_free(ssl);
-#endif /* NO_SSL */
- } else if ((c = calloc(1, sizeof(*c) + 2 * URI_MAX)) == NULL) {
-#if !defined(NO_SSL)
- if (ssl)
- SSL_free(ssl);
-#endif /* NO_SSL */
- (void) closesocket(sock);
- _shttpd_elog(l, NULL, "add_socket: calloc: %s", strerror(ERRNO));
- } else {
- c->rem.conn = c->loc.conn = c;
- c->ctx = ctx;
- c->worker = worker;
- c->sa = sa;
- c->birth_time = _shttpd_current_time;
- c->expire_time = _shttpd_current_time + EXPIRE_TIME;
-
- (void) getsockname(sock, &sa.u.sa, &sa.len);
- c->loc_port = sa.u.sin.sin_port;
-
- _shttpd_set_close_on_exec(sock);
-
- c->loc.io_class = NULL;
-
- c->rem.io_class = &_shttpd_io_socket;
- c->rem.chan.sock = sock;
-
- /* Set IO buffers */
- c->loc.io.buf = (char *) (c + 1);
- c->rem.io.buf = c->loc.io.buf + URI_MAX;
- c->loc.io.size = c->rem.io.size = URI_MAX;
-
-#if !defined(NO_SSL)
- if (is_ssl) {
- c->rem.io_class = &_shttpd_io_ssl;
- c->rem.chan.ssl.sock = sock;
- c->rem.chan.ssl.ssl = ssl;
- _shttpd_ssl_handshake(&c->rem);
- }
-#endif /* NO_SSL */
-
- LL_TAIL(&worker->connections, &c->link);
- worker->num_conns++;
-
- DBG(("%s:%hu connected (socket %d)",
- inet_ntoa(* (struct in_addr *) &sa.u.sin.sin_addr.s_addr),
- ntohs(sa.u.sin.sin_port), sock));
- }
-}
-
-static struct worker *
-first_worker(struct shttpd_ctx *ctx)
-{
- return (LL_ENTRY(ctx->workers.next, struct worker, link));
-}
-
-static void
-pass_socket(struct shttpd_ctx *ctx, int sock, int is_ssl)
-{
- struct llhead *lp;
- struct worker *worker, *lazy;
- int buf[3];
-
- lazy = first_worker(ctx);
-
- /* Find least busy worker */
- LL_FOREACH(&ctx->workers, lp) {
- worker = LL_ENTRY(lp, struct worker, link);
- if (worker->num_conns < lazy->num_conns)
- lazy = worker;
- }
-
- buf[0] = CTL_PASS_SOCKET;
- buf[1] = sock;
- buf[2] = is_ssl;
-
- (void) send(lazy->ctl[1], (void *) buf, sizeof(buf), 0);
-}
-
-static int
-set_ports(struct shttpd_ctx *ctx, const char *p)
-{
- int sock, len, is_ssl, port;
- struct listener *l;
-
-
- free_list(&ctx->listeners, &listener_destructor);
-
- FOR_EACH_WORD_IN_LIST(p, len) {
-
- is_ssl = p[len - 1] == 's' ? 1 : 0;
- port = atoi(p);
-
- if ((sock = shttpd_open_listening_port(port)) == -1) {
- _shttpd_elog(E_LOG, NULL, "cannot open port %d", port);
- goto fail;
- } else if (is_ssl && ctx->ssl_ctx == NULL) {
- (void) closesocket(sock);
- _shttpd_elog(E_LOG, NULL, "cannot add SSL socket, "
- "please specify certificate file");
- goto fail;
- } else if ((l = calloc(1, sizeof(*l))) == NULL) {
- (void) closesocket(sock);
- _shttpd_elog(E_LOG, NULL, "cannot allocate listener");
- goto fail;
- } else {
- l->is_ssl = is_ssl;
- l->sock = sock;
- l->ctx = ctx;
- LL_TAIL(&ctx->listeners, &l->link);
- DBG(("shttpd_listen: added socket %d", sock));
- }
- }
-
- return (TRUE);
-fail:
- free_list(&ctx->listeners, &listener_destructor);
- return (FALSE);
-}
-
-static void
-read_stream(struct stream *stream)
-{
- int n, len;
-
- len = io_space_len(&stream->io);
- assert(len > 0);
-
- /* Do not read more that needed */
- if (stream->content_len > 0 &&
- stream->io.total + len > stream->content_len)
- len = stream->content_len - stream->io.total;
-
- /* Read from underlying channel */
- assert(stream->io_class != NULL);
- n = stream->io_class->read(stream, io_space(&stream->io), len);
-
- if (n > 0)
- io_inc_head(&stream->io, n);
- else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK))
- n = n; /* Ignore EINTR and EAGAIN */
- else if (!(stream->flags & FLAG_DONT_CLOSE))
- _shttpd_stop_stream(stream);
-
- DBG(("read_stream (%d %s): read %d/%d/%lu bytes (errno %d)",
- stream->conn->rem.chan.sock,
- stream->io_class ? stream->io_class->name : "(null)",
- n, len, (unsigned long) stream->io.total, ERRNO));
-
- /*
- * Close the local stream if everything was read
- * XXX We do not close the remote stream though! It may be
- * a POST data completed transfer, we do not want the socket
- * to be closed.
- */
- if (stream->content_len > 0 && stream == &stream->conn->loc) {
- assert(stream->io.total <= stream->content_len);
- if (stream->io.total == stream->content_len)
- _shttpd_stop_stream(stream);
- }
-
- stream->conn->expire_time = _shttpd_current_time + EXPIRE_TIME;
-}
-
-static void
-write_stream(struct stream *from, struct stream *to)
-{
- int n, len;
-
- len = io_data_len(&from->io);
- assert(len > 0);
-
- /* TODO: should be assert on CAN_WRITE flag */
- n = to->io_class->write(to, io_data(&from->io), len);
- to->conn->expire_time = _shttpd_current_time + EXPIRE_TIME;
- DBG(("write_stream (%d %s): written %d/%d bytes (errno %d)",
- to->conn->rem.chan.sock,
- to->io_class ? to->io_class->name : "(null)", n, len, ERRNO));
-
- if (n > 0)
- io_inc_tail(&from->io, n);
- else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK))
- n = n; /* Ignore EINTR and EAGAIN */
- else if (!(to->flags & FLAG_DONT_CLOSE))
- _shttpd_stop_stream(to);
-}
-
-
-static void
-connection_desctructor(struct llhead *lp)
-{
- struct conn *c = LL_ENTRY(lp, struct conn, link);
- static const struct vec vec = {"close", 5};
- int do_close;
-
- DBG(("Disconnecting %d (%.*s)", c->rem.chan.sock,
- c->ch.connection.v_vec.len, c->ch.connection.v_vec.ptr));
-
- if (c->request != NULL && c->ctx->access_log != NULL)
- _shttpd_log_access(c->ctx->access_log, c);
-
- /* In inetd mode, exit if request is finished. */
- if (IS_TRUE(c->ctx, OPT_INETD))
- exit(0);
-
- if (c->loc.io_class != NULL && c->loc.io_class->close != NULL)
- c->loc.io_class->close(&c->loc);
-
- /*
- * Check the "Connection: " header before we free c->request
- * If it its 'keep-alive', then do not close the connection
- */
- do_close = (c->ch.connection.v_vec.len >= vec.len &&
- !_shttpd_strncasecmp(vec.ptr,c->ch.connection.v_vec.ptr,vec.len)) ||
- (c->major_version < 1 ||
- (c->major_version >= 1 && c->minor_version < 1));
-
- if (c->request)
- free(c->request);
- if (c->uri)
- free(c->uri);
-
- /* Keep the connection open only if we have Content-Length set */
- if (!do_close && c->loc.content_len > 0) {
- c->loc.io_class = NULL;
- c->loc.flags = 0;
- c->loc.content_len = 0;
- c->rem.flags = FLAG_W | FLAG_R | FLAG_SSL_ACCEPTED;
- c->query = c->request = c->uri = c->path_info = NULL;
- c->mime_type.len = 0;
- (void) memset(&c->ch, 0, sizeof(c->ch));
- io_clear(&c->loc.io);
- c->birth_time = _shttpd_current_time;
- if (io_data_len(&c->rem.io) > 0)
- process_connection(c, 0, 0);
- } else {
- if (c->rem.io_class != NULL)
- c->rem.io_class->close(&c->rem);
-
- LL_DEL(&c->link);
- c->worker->num_conns--;
- assert(c->worker->num_conns >= 0);
-
- free(c);
- }
-}
-
-static void
-worker_destructor(struct llhead *lp)
-{
- struct worker *worker = LL_ENTRY(lp, struct worker, link);
-
- free_list(&worker->connections, connection_desctructor);
- free(worker);
-}
-
-static int
-is_allowed(const struct shttpd_ctx *ctx, const struct usa *usa)
-{
- const struct acl *acl;
- const struct llhead *lp;
- int allowed = '+';
- uint32_t ip;
-
- LL_FOREACH(&ctx->acl, lp) {
- acl = LL_ENTRY(lp, struct acl, link);
- (void) memcpy(&ip, &usa->u.sin.sin_addr, sizeof(ip));
- if (acl->ip == (ntohl(ip) & acl->mask))
- allowed = acl->flag;
- }
-
- return (allowed == '+');
-}
-
-static void
-add_to_set(int fd, fd_set *set, int *max_fd)
-{
- FD_SET(fd, set);
- if (fd > *max_fd)
- *max_fd = fd;
-}
-
-static void
-process_connection(struct conn *c, int remote_ready, int local_ready)
-{
- /* Read from remote end if it is ready */
- if (remote_ready && io_space_len(&c->rem.io))
- read_stream(&c->rem);
-
- /* If the request is not parsed yet, do so */
- if (!(c->rem.flags & FLAG_HEADERS_PARSED))
- parse_http_request(c);
-
- DBG(("loc: %d [%.*s]", (int) io_data_len(&c->loc.io),
- (int) io_data_len(&c->loc.io), io_data(&c->loc.io)));
- DBG(("rem: %d [%.*s]", (int) io_data_len(&c->rem.io),
- (int) io_data_len(&c->rem.io), io_data(&c->rem.io)));
-
- /* Read from the local end if it is ready */
- if (local_ready && io_space_len(&c->loc.io))
- read_stream(&c->loc);
-
- if (io_data_len(&c->rem.io) > 0 && (c->loc.flags & FLAG_W) &&
- c->loc.io_class != NULL && c->loc.io_class->write != NULL)
- write_stream(&c->rem, &c->loc);
-
- if (io_data_len(&c->loc.io) > 0 && c->rem.io_class != NULL)
- write_stream(&c->loc, &c->rem);
-
- /* Check whether we should close this connection */
- if ((_shttpd_current_time > c->expire_time) ||
- (c->rem.flags & FLAG_CLOSED) ||
- ((c->loc.flags & FLAG_CLOSED) && !io_data_len(&c->loc.io)))
- connection_desctructor(&c->link);
-}
-
-static int
-num_workers(const struct shttpd_ctx *ctx)
-{
- char *p = ctx->options[OPT_THREADS];
- return (p ? atoi(p) : 1);
-}
-
-static void
-handle_connected_socket(struct shttpd_ctx *ctx,
- struct usa *sap, int sock, int is_ssl)
-{
-#if !defined(_WIN32)
- if (sock >= (int) FD_SETSIZE) {
- _shttpd_elog(E_LOG, NULL, "ctx %p: discarding "
- "socket %d, too busy", ctx, sock);
- (void) closesocket(sock);
- } else
-#endif /* !_WIN32 */
- if (!is_allowed(ctx, sap)) {
- _shttpd_elog(E_LOG, NULL, "%s is not allowed to connect",
- inet_ntoa(sap->u.sin.sin_addr));
- (void) closesocket(sock);
- } else if (num_workers(ctx) > 1) {
- pass_socket(ctx, sock, is_ssl);
- } else {
- add_socket(first_worker(ctx), sock, is_ssl);
- }
-}
-
-static int
-do_select(int max_fd, fd_set *read_set, fd_set *write_set, int milliseconds)
-{
- struct timeval tv;
- int n;
-
- tv.tv_sec = milliseconds / 1000;
- tv.tv_usec = (milliseconds % 1000) * 1000;
-
- /* Check IO readiness */
- if ((n = select(max_fd + 1, read_set, write_set, NULL, &tv)) < 0) {
-#ifdef _WIN32
- /*
- * On windows, if read_set and write_set are empty,
- * select() returns "Invalid parameter" error
- * (at least on my Windows XP Pro). So in this case,
- * we sleep here.
- */
- Sleep(milliseconds);
-#endif /* _WIN32 */
- DBG(("select: %d", ERRNO));
- }
-
- return (n);
-}
-
-static int
-multiplex_worker_sockets(const struct worker *worker, int *max_fd,
- fd_set *read_set, fd_set *write_set)
-{
- struct llhead *lp;
- struct conn *c;
- int nowait = FALSE;
-
- /* Add control socket */
- add_to_set(worker->ctl[0], read_set, max_fd);
-
- /* Multiplex streams */
- LL_FOREACH(&worker->connections, lp) {
- c = LL_ENTRY(lp, struct conn, link);
-
- /* If there is a space in remote IO, check remote socket */
- if (io_space_len(&c->rem.io))
- add_to_set(c->rem.chan.fd, read_set, max_fd);
-
-#if !defined(NO_CGI)
- /*
- * If there is a space in local IO, and local endpoint is
- * CGI, check local socket for read availability
- */
- if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
- c->loc.io_class == &_shttpd_io_cgi)
- add_to_set(c->loc.chan.fd, read_set, max_fd);
-
- /*
- * If there is some data read from remote socket, and
- * local endpoint is CGI, check local for write availability
- */
- if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
- c->loc.io_class == &_shttpd_io_cgi)
- add_to_set(c->loc.chan.fd, write_set, max_fd);
-#endif /* NO_CGI */
-
- /*
- * If there is some data read from local endpoint, check the
- * remote socket for write availability
- */
- if (io_data_len(&c->loc.io) && !(c->loc.flags & FLAG_SUSPEND))
- add_to_set(c->rem.chan.fd, write_set, max_fd);
-
- /*
- * Set select wait interval to zero if FLAG_ALWAYS_READY set
- */
- if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
- (c->loc.flags & FLAG_ALWAYS_READY))
- nowait = TRUE;
-
- if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
- (c->loc.flags & FLAG_ALWAYS_READY))
- nowait = TRUE;
- }
-
- return (nowait);
-}
-
-int
-shttpd_join(struct shttpd_ctx *ctx,
- fd_set *read_set, fd_set *write_set, int *max_fd)
-{
- struct llhead *lp;
- struct listener *l;
- int nowait = FALSE;
-
- /* Add listening sockets to the read set */
- LL_FOREACH(&ctx->listeners, lp) {
- l = LL_ENTRY(lp, struct listener, link);
- add_to_set(l->sock, read_set, max_fd);
- DBG(("FD_SET(%d) (listening)", l->sock));
- }
-
- if (num_workers(ctx) == 1)
- nowait = multiplex_worker_sockets(first_worker(ctx), max_fd,
- read_set, write_set);
-
- return (nowait);
-}
-
-
-static void
-process_worker_sockets(struct worker *worker, fd_set *read_set)
-{
- struct llhead *lp, *tmp;
- int cmd, skt[2], sock = worker->ctl[0];
- struct conn *c;
-
- /* Check if new socket is passed to us over the control socket */
- if (FD_ISSET(worker->ctl[0], read_set))
- while (recv(sock, (void *) &cmd, sizeof(cmd), 0) == sizeof(cmd))
- switch (cmd) {
- case CTL_PASS_SOCKET:
- (void)recv(sock, (void *) &skt, sizeof(skt), 0);
- add_socket(worker, skt[0], skt[1]);
- break;
- case CTL_WAKEUP:
- (void)recv(sock, (void *) &c, sizeof(c), 0);
- c->loc.flags &= FLAG_SUSPEND;
- break;
- default:
- _shttpd_elog(E_FATAL, NULL, "ctx %p: ctl cmd %d",
- worker->ctx, cmd);
- break;
- }
-
- /* Process all connections */
- LL_FOREACH_SAFE(&worker->connections, lp, tmp) {
- c = LL_ENTRY(lp, struct conn, link);
- process_connection(c, FD_ISSET(c->rem.chan.sock, read_set),
- c->loc.io_class != NULL &&
- ((c->loc.flags & FLAG_ALWAYS_READY)
-#if !defined(NO_CGI)
- || (c->loc.io_class == &_shttpd_io_cgi &&
- FD_ISSET(c->loc.chan.fd, read_set))
-#endif /* NO_CGI */
- ));
- }
-}
-
-/*
- * One iteration of server loop. This is the core of the data exchange.
- */
-void
-shttpd_poll(struct shttpd_ctx *ctx, int milliseconds)
-{
- struct llhead *lp;
- struct listener *l;
- fd_set read_set, write_set;
- int sock, max_fd = -1;
- struct usa sa;
-
- _shttpd_current_time = time(0);
- FD_ZERO(&read_set);
- FD_ZERO(&write_set);
-
- if (shttpd_join(ctx, &read_set, &write_set, &max_fd))
- milliseconds = 0;
-
- if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
- return;;
-
- /* Check for incoming connections on listener sockets */
- LL_FOREACH(&ctx->listeners, lp) {
- l = LL_ENTRY(lp, struct listener, link);
- if (!FD_ISSET(l->sock, &read_set))
- continue;
- do {
- sa.len = sizeof(sa.u.sin);
- if ((sock = accept(l->sock, &sa.u.sa, &sa.len)) != -1)
- handle_connected_socket(ctx,&sa,sock,l->is_ssl);
- } while (sock != -1);
- }
-
- if (num_workers(ctx) == 1)
- process_worker_sockets(first_worker(ctx), &read_set);
-}
-
-/*
- * Deallocate shttpd object, free up the resources
- */
-void
-shttpd_fini(struct shttpd_ctx *ctx)
-{
- size_t i;
-
- free_list(&ctx->workers, worker_destructor);
- free_list(&ctx->registered_uris, registered_uri_destructor);
- free_list(&ctx->acl, acl_destructor);
- free_list(&ctx->listeners, listener_destructor);
-#if !defined(NO_SSI)
- free_list(&ctx->ssi_funcs, _shttpd_ssi_func_destructor);
-#endif /* !NO_SSI */
-
- for (i = 0; i < NELEMS(ctx->options); i++)
- if (ctx->options[i] != NULL)
- free(ctx->options[i]);
-
- if (ctx->access_log) (void) fclose(ctx->access_log);
- if (ctx->error_log) (void) fclose(ctx->error_log);
-
- /* TODO: free SSL context */
-
- free(ctx);
-}
-
-/*
- * UNIX socketpair() implementation. Why? Because Windows does not have it.
- * Return 0 on success, -1 on error.
- */
-int
-shttpd_socketpair(int sp[2])
-{
- struct sockaddr_in sa;
- int sock, ret = -1;
- socklen_t len = sizeof(sa);
-
- sp[0] = sp[1] = -1;
-
- (void) memset(&sa, 0, sizeof(sa));
- sa.sin_family = AF_INET;
- sa.sin_port = htons(0);
- sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) != -1 &&
- !bind(sock, (struct sockaddr *) &sa, len) &&
- !listen(sock, 1) &&
- !getsockname(sock, (struct sockaddr *) &sa, &len) &&
- (sp[0] = socket(AF_INET, SOCK_STREAM, 6)) != -1 &&
- !connect(sp[0], (struct sockaddr *) &sa, len) &&
- (sp[1] = accept(sock,(struct sockaddr *) &sa, &len)) != -1) {
-
- /* Success */
- ret = 0;
- } else {
-
- /* Failure, close descriptors */
- if (sp[0] != -1)
- (void) closesocket(sp[0]);
- if (sp[1] != -1)
- (void) closesocket(sp[1]);
- }
-
- (void) closesocket(sock);
- (void) _shttpd_set_non_blocking_mode(sp[0]);
- (void) _shttpd_set_non_blocking_mode(sp[1]);
-
-#ifndef _WIN32
- (void) fcntl(sp[0], F_SETFD, FD_CLOEXEC);
- (void) fcntl(sp[1], F_SETFD, FD_CLOEXEC);
-#endif /* _WIN32*/
-
- return (ret);
-}
-
-static int isbyte(int n) { return (n >= 0 && n <= 255); }
-
-static int
-set_inetd(struct shttpd_ctx *ctx, const char *flag)
-{
- ctx = NULL; /* Unused */
-
- if (_shttpd_is_true(flag)) {
- shttpd_set_option(ctx, "ports", NULL);
- (void) freopen("/dev/null", "a", stderr);
- add_socket(first_worker(ctx), 0, 0);
- }
-
- return (TRUE);
-}
-
-static int
-set_uid(struct shttpd_ctx *ctx, const char *uid)
-{
- struct passwd *pw;
-
- ctx = NULL; /* Unused */
-
-#if !defined(_WIN32)
- if ((pw = getpwnam(uid)) == NULL)
- _shttpd_elog(E_FATAL, 0, "%s: unknown user [%s]", __func__, uid);
- else if (setgid(pw->pw_gid) == -1)
- _shttpd_elog(E_FATAL, NULL, "%s: setgid(%s): %s",
- __func__, uid, strerror(errno));
- else if (setuid(pw->pw_uid) == -1)
- _shttpd_elog(E_FATAL, NULL, "%s: setuid(%s): %s",
- __func__, uid, strerror(errno));
-#endif /* !_WIN32 */
- return (TRUE);
-}
-
-static int
-set_acl(struct shttpd_ctx *ctx, const char *s)
-{
- struct acl *acl = NULL;
- char flag;
- int len, a, b, c, d, n, mask;
-
- /* Delete the old ACLs if any */
- free_list(&ctx->acl, acl_destructor);
-
- FOR_EACH_WORD_IN_LIST(s, len) {
-
- mask = 32;
-
- if (sscanf(s, "%c%d.%d.%d.%d%n",&flag,&a,&b,&c,&d,&n) != 5) {
- _shttpd_elog(E_FATAL, NULL, "[%s]: subnet must be "
- "[+|-]x.x.x.x[/x]", s);
- } else if (flag != '+' && flag != '-') {
- _shttpd_elog(E_FATAL, NULL, "flag must be + or -: [%s]", s);
- } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
- _shttpd_elog(E_FATAL, NULL, "bad ip address: [%s]", s);
- } else if ((acl = malloc(sizeof(*acl))) == NULL) {
- _shttpd_elog(E_FATAL, NULL, "%s", "cannot malloc subnet");
- } else if (sscanf(s + n, "/%d", &mask) == 0) {
- /* Do nothing, no mask specified */
- } else if (mask < 0 || mask > 32) {
- _shttpd_elog(E_FATAL, NULL, "bad subnet mask: %d [%s]", n, s);
- }
-
- acl->ip = (a << 24) | (b << 16) | (c << 8) | d;
- acl->mask = mask ? 0xffffffffU << (32 - mask) : 0;
- acl->flag = flag;
- LL_TAIL(&ctx->acl, &acl->link);
- }
-
- return (TRUE);
-}
-
-#ifndef NO_SSL
-/*
- * Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
- */
-static int
-set_ssl(struct shttpd_ctx *ctx, const char *pem)
-{
- SSL_CTX *CTX;
- void *lib;
- struct ssl_func *fp;
- int retval = FALSE;
-
- /* Load SSL library dynamically */
- if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL) {
- _shttpd_elog(E_LOG, NULL, "set_ssl: cannot load %s", SSL_LIB);
- return (FALSE);
- }
-
- for (fp = ssl_sw; fp->name != NULL; fp++)
- if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL) {
- _shttpd_elog(E_LOG, NULL,"set_ssl: cannot find %s", fp->name);
- return (FALSE);
- }
-
- /* Initialize SSL crap */
- SSL_library_init();
-
- if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
- _shttpd_elog(E_LOG, NULL, "SSL_CTX_new error");
- else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
- _shttpd_elog(E_LOG, NULL, "cannot open %s", pem);
- else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
- _shttpd_elog(E_LOG, NULL, "cannot open %s", pem);
- else
- retval = TRUE;
-
- ctx->ssl_ctx = CTX;
-
- return (retval);
-}
-#endif /* NO_SSL */
-
-static int
-open_log_file(FILE **fpp, const char *path)
-{
- int retval = TRUE;
-
- if (*fpp != NULL)
- (void) fclose(*fpp);
-
- if (path == NULL) {
- *fpp = NULL;
- } else if ((*fpp = fopen(path, "a")) == NULL) {
- _shttpd_elog(E_LOG, NULL, "cannot open log file %s: %s",
- path, strerror(errno));
- retval = FALSE;
- }
-
- return (retval);
-}
-
-static int set_alog(struct shttpd_ctx *ctx, const char *path) {
- return (open_log_file(&ctx->access_log, path));
-}
-
-static int set_elog(struct shttpd_ctx *ctx, const char *path) {
- return (open_log_file(&ctx->error_log, path));
-}
-
-static void show_cfg_page(struct shttpd_arg *arg);
-
-static int
-set_cfg_uri(struct shttpd_ctx *ctx, const char *uri)
-{
- free_list(&ctx->registered_uris, ®istered_uri_destructor);
-
- if (uri != NULL)
- shttpd_register_uri(ctx, uri, &show_cfg_page, ctx);
-
- return (TRUE);
-}
-
-static struct worker *
-add_worker(struct shttpd_ctx *ctx)
-{
- struct worker *worker;
-
- if ((worker = calloc(1, sizeof(*worker))) == NULL)
- _shttpd_elog(E_FATAL, NULL, "Cannot allocate worker");
- LL_INIT(&worker->connections);
- worker->ctx = ctx;
- (void) shttpd_socketpair(worker->ctl);
- LL_TAIL(&ctx->workers, &worker->link);
-
- return (worker);
-}
-
-#if !defined(NO_THREADS)
-static void
-poll_worker(struct worker *worker, int milliseconds)
-{
- fd_set read_set, write_set;
- int max_fd = -1;
-
- FD_ZERO(&read_set);
- FD_ZERO(&write_set);
-
- if (multiplex_worker_sockets(worker, &max_fd, &read_set, &write_set))
- milliseconds = 0;
-
- if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
- return;;
-
- process_worker_sockets(worker, &read_set);
-}
-
-static void
-worker_function(void *param)
-{
- struct worker *worker = param;
-
- while (worker->exit_flag == 0)
- poll_worker(worker, 1000 * 10);
-
- free_list(&worker->connections, connection_desctructor);
- free(worker);
-}
-
-static int
-set_workers(struct shttpd_ctx *ctx, const char *value)
-{
- int new_num, old_num;
- struct llhead *lp, *tmp;
- struct worker *worker;
-
- new_num = atoi(value);
- old_num = 0;
- LL_FOREACH(&ctx->workers, lp)
- old_num++;
-
- if (new_num == 1) {
- if (old_num > 1)
- /* Stop old threads */
- LL_FOREACH_SAFE(&ctx->workers, lp, tmp) {
- worker = LL_ENTRY(lp, struct worker, link);
- LL_DEL(&worker->link);
- worker = LL_ENTRY(lp, struct worker, link);
- worker->exit_flag = 1;
- }
- (void) add_worker(ctx);
- } else {
- /* FIXME: we cannot here reduce the number of threads */
- while (new_num > 1 && new_num > old_num) {
- worker = add_worker(ctx);
- _beginthread(worker_function, 0, worker);
- old_num++;
- }
- }
-
- return (TRUE);
-}
-#endif /* NO_THREADS */
-
-static const struct opt {
- int index; /* Index in shttpd_ctx */
- const char *name; /* Option name in config file */
- const char *description; /* Description */
- const char *default_value; /* Default option value */
- int (*setter)(struct shttpd_ctx *, const char *);
-} known_options[] = {
- {OPT_ROOT, "root", "\tWeb root directory", ".", NULL},
- {OPT_INDEX_FILES, "index_files", "Index files", INDEX_FILES, NULL},
-#ifndef NO_SSL
- {OPT_SSL_CERTIFICATE, "ssl_cert", "SSL certificate file", NULL,set_ssl},
-#endif /* NO_SSL */
- {OPT_PORTS, "ports", "Listening ports", LISTENING_PORTS, set_ports},
- {OPT_DIR_LIST, "dir_list", "Directory listing", "yes", NULL},
- {OPT_CFG_URI, "cfg_uri", "Config uri", NULL, set_cfg_uri},
- {OPT_PROTECT, "protect", "URI to htpasswd mapping", NULL, NULL},
-#ifndef NO_CGI
- {OPT_CGI_EXTENSIONS, "cgi_ext", "CGI extensions", CGI_EXT, NULL},
- {OPT_CGI_INTERPRETER, "cgi_interp", "CGI interpreter", NULL, NULL},
- {OPT_CGI_ENVIRONMENT, "cgi_env", "Additional CGI env vars", NULL, NULL},
-#endif /* NO_CGI */
- {OPT_SSI_EXTENSIONS, "ssi_ext", "SSI extensions", SSI_EXT, NULL},
-#ifndef NO_AUTH
- {OPT_AUTH_REALM, "auth_realm", "Authentication domain name",REALM,NULL},
- {OPT_AUTH_GPASSWD, "auth_gpass", "Global passwords file", NULL, NULL},
- {OPT_AUTH_PUT, "auth_PUT", "PUT,DELETE auth file", NULL, NULL},
-#endif /* !NO_AUTH */
-#ifdef _WIN32
- {OPT_SERVICE, "service", "Manage WinNNT service (install"
- "|uninstall)", NULL, _shttpd_set_nt_service},
- {OPT_HIDE, "systray", "Hide console, show icon on systray",
- "no", _shttpd_set_systray},
-#else
- {OPT_INETD, "inetd", "Inetd mode", "no", set_inetd},
- {OPT_UID, "uid", "\tRun as user", NULL, set_uid},
-#endif /* _WIN32 */
- {OPT_ACCESS_LOG, "access_log", "Access log file", NULL, set_alog},
- {OPT_ERROR_LOG, "error_log", "Error log file", NULL, set_elog},
- {OPT_MIME_TYPES, "mime_types", "Additional mime types list", NULL,NULL},
- {OPT_ALIASES, "aliases", "Path=URI mappings", NULL, NULL},
- {OPT_ACL, "acl", "\tAllow/deny IP addresses/subnets", NULL, set_acl},
-#if !defined(NO_THREADS)
- {OPT_THREADS, "threads", "Number of worker threads", "1", set_workers},
-#endif /* !NO_THREADS */
- {-1, NULL, NULL, NULL, NULL}
-};
-
-static const struct opt *
-find_opt(const char *opt_name)
-{
- int i;
-
- for (i = 0; known_options[i].name != NULL; i++)
- if (!strcmp(opt_name, known_options[i].name))
- return (known_options + i);
-
- _shttpd_elog(E_FATAL, NULL, "no such option: [%s]", opt_name);
-
- /* UNREACHABLE */
- return (NULL);
-}
-
-int
-shttpd_set_option(struct shttpd_ctx *ctx, const char *opt, const char *val)
-{
- const struct opt *o = find_opt(opt);
- int retval = TRUE;
-
- /* Call option setter first, so it can use both new and old values */
- if (o->setter != NULL)
- retval = o->setter(ctx, val);
-
- /* Free old value if any */
- if (ctx->options[o->index] != NULL)
- free(ctx->options[o->index]);
-
- /* Set new option value */
- ctx->options[o->index] = val ? _shttpd_strdup(val) : NULL;
-
- return (retval);
-}
-
-static void
-show_cfg_page(struct shttpd_arg *arg)
-{
- struct shttpd_ctx *ctx = arg->user_data;
- char opt_name[20], value[BUFSIZ];
- const struct opt *o;
-
- opt_name[0] = value[0] = '\0';
-
- if (!strcmp(shttpd_get_env(arg, "REQUEST_METHOD"), "POST")) {
- if (arg->flags & SHTTPD_MORE_POST_DATA)
- return;
- (void) shttpd_get_var("o", arg->in.buf, arg->in.len,
- opt_name, sizeof(opt_name));
- (void) shttpd_get_var("v", arg->in.buf, arg->in.len,
- value, sizeof(value));
- shttpd_set_option(ctx, opt_name, value[0] ? value : NULL);
- }
-
- shttpd_printf(arg, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
- "<html><body><h1>SHTTPD v. %s</h1>", shttpd_version());
-
- shttpd_printf(arg, "%s", "<table border=1"
- "<tr><th>Option</th><th>Description</th>"
- "<th colspan=2>Value</th></tr>");
-
- if (opt_name[0] != '\0' && value[0] != '\0')
- shttpd_printf(arg, "<p style='color: green'>Saved: %s=%s</p>",
- opt_name, value[0] ? value : "NULL");
-
-
- for (o = known_options; o->name != NULL; o++) {
- shttpd_printf(arg,
- "<form method=post><tr><td>%s</td><td>%s</td>"
- "<input type=hidden name=o value='%s'>"
- "<td><input type=text name=v value='%s'></td>"
- "<td><input type=submit value=save></td></form></tr>",
- o->name, o->description, o->name,
- ctx->options[o->index] ? ctx->options[o->index] : "");
- }
-
- shttpd_printf(arg, "%s", "</table></body></html>");
- arg->flags |= SHTTPD_END_OF_OUTPUT;
-}
-
-/*
- * Show usage string and exit.
- */
-void
-_shttpd_usage(const char *prog)
-{
- const struct opt *o;
-
- (void) fprintf(stderr,
- "SHTTPD version %s (c) Sergey Lyubka\n"
- "usage: %s [options] [config_file]\n", VERSION, prog);
-
-#if !defined(NO_AUTH)
- fprintf(stderr, " -A <htpasswd_file> <realm> <user> <passwd>\n");
-#endif /* NO_AUTH */
-
- for (o = known_options; o->name != NULL; o++) {
- (void) fprintf(stderr, " -%s\t%s", o->name, o->description);
- if (o->default_value != NULL)
- fprintf(stderr, " (default: %s)", o->default_value);
- fputc('\n', stderr);
- }
-
- exit(EXIT_FAILURE);
-}
-
-static void
-set_opt(struct shttpd_ctx *ctx, const char *opt, const char *value)
-{
- const struct opt *o;
-
- o = find_opt(opt);
- if (ctx->options[o->index] != NULL)
- free(ctx->options[o->index]);
- ctx->options[o->index] = _shttpd_strdup(value);
-}
-
-static void
-process_command_line_arguments(struct shttpd_ctx *ctx, char *argv[])
-{
- const char *config_file = CONFIG_FILE;
- char line[BUFSIZ], opt[BUFSIZ],
- val[BUFSIZ], path[FILENAME_MAX], *p;
- FILE *fp;
- size_t i, line_no = 0;
-
- /* First find out, which config file to open */
- for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
- if (argv[i + 1] == NULL)
- _shttpd_usage(argv[0]);
-
- if (argv[i] != NULL && argv[i + 1] != NULL) {
- /* More than one non-option arguments are given w*/
- _shttpd_usage(argv[0]);
- } else if (argv[i] != NULL) {
- /* Just one non-option argument is given, this is config file */
- config_file = argv[i];
- } else {
- /* No config file specified. Look for one where shttpd lives */
- if ((p = strrchr(argv[0], DIRSEP)) != 0) {
- _shttpd_snprintf(path, sizeof(path), "%.*s%s",
- p - argv[0] + 1, argv[0], config_file);
- config_file = path;
- }
- }
-
- fp = fopen(config_file, "r");
-
- /* If config file was set in command line and open failed, exit */
- if (fp == NULL && argv[i] != NULL)
- _shttpd_elog(E_FATAL, NULL, "cannot open config file %s: %s",
- config_file, strerror(errno));
-
- if (fp != NULL) {
-
- _shttpd_elog(E_LOG, NULL, "Loading config file %s", config_file);
-
- /* Loop over the lines in config file */
- while (fgets(line, sizeof(line), fp) != NULL) {
-
- line_no++;
-
- /* Ignore empty lines and comments */
- if (line[0] == '#' || line[0] == '\n')
- continue;
-
- if (sscanf(line, "%s %[^\n#]", opt, val) != 2)
- _shttpd_elog(E_FATAL, NULL, "line %d in %s is invalid",
- line_no, config_file);
-
- set_opt(ctx, opt, val);
- }
-
- (void) fclose(fp);
- }
-
- /* Now pass through the command line options */
- for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
- set_opt(ctx, &argv[i][1], argv[i + 1]);
-}
-
-struct shttpd_ctx *
-shttpd_init(int argc, char *argv[])
-{
- struct shttpd_ctx *ctx;
- struct tm *tm;
- const struct opt *o;
-
- if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
- _shttpd_elog(E_FATAL, NULL, "cannot allocate shttpd context");
-
- LL_INIT(&ctx->registered_uris);
- LL_INIT(&ctx->error_handlers);
- LL_INIT(&ctx->acl);
- LL_INIT(&ctx->ssi_funcs);
- LL_INIT(&ctx->listeners);
- LL_INIT(&ctx->workers);
-
- /* Initialize options. First pass: set default option values */
- for (o = known_options; o->name != NULL; o++)
- ctx->options[o->index] = o->default_value ?
- _shttpd_strdup(o->default_value) : NULL;
-
- /* Second and third passes: config file and argv */
- if (argc > 0 && argv != NULL)
- process_command_line_arguments(ctx, argv);
-
- /* Call setter functions */
- for (o = known_options; o->name != NULL; o++)
- if (o->setter && ctx->options[o->index] != NULL)
- if (o->setter(ctx, ctx->options[o->index]) == FALSE) {
- shttpd_fini(ctx);
- return (NULL);
- }
-
- _shttpd_current_time = time(NULL);
- tm = localtime(&_shttpd_current_time);
- _shttpd_tz_offset = 0;
-
- if (num_workers(ctx) == 1)
- (void) add_worker(ctx);
-#if 0
- tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
-#endif
-
-#ifdef _WIN32
- {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);}
-#endif /* _WIN32 */
-
- return (ctx);
-}
diff --git a/vendor/shttpd/shttpd.h b/vendor/shttpd/shttpd.h
deleted file mode 100644
index d475b06..0000000
--- a/vendor/shttpd/shttpd.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- *
- * $Id: shttpd.h,v 1.18 2008/08/23 08:34:50 drozd Exp $
- */
-
-#ifndef SHTTPD_HEADER_INCLUDED
-#define SHTTPD_HEADER_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-struct ubuf {
- char *buf; /* Buffer pointer */
- int len; /* Size of a buffer */
- int num_bytes; /* Bytes processed by callback */
-};
-
-/*
- * This structure is passed to the user callback function
- */
-struct shttpd_arg {
- void *priv; /* Private! Do not touch! */
- void *state; /* User state */
- void *user_data; /* Data from register_uri() */
- struct ubuf in; /* Input is here, POST data */
- struct ubuf out; /* Output goes here */
-
- unsigned int flags;
-#define SHTTPD_END_OF_OUTPUT 1 /* No more data do send */
-#define SHTTPD_CONNECTION_ERROR 2 /* Server closed the connection */
-#define SHTTPD_MORE_POST_DATA 4 /* arg->in has incomplete data */
-#define SHTTPD_POST_BUFFER_FULL 8 /* arg->in has max data */
-#define SHTTPD_SSI_EVAL_TRUE 16 /* SSI eval callback must set it*/
-#define SHTTPD_SUSPEND 32 /* User wants to suspend output */
-};
-
-/*
- * User callback function. Called when certain registered URLs have been
- * requested. These are the requirements to the callback function:
- *
- * 1. It must copy data into 'out.buf' buffer, not more than 'out.len' bytes,
- * and record how many bytes are copied, into 'out.num_bytes'
- * 2. It must not call any blocking functions
- * 3. It must set SHTTPD_END_OF_OUTPUT flag when there is no more data to send
- * 4. For POST requests, it must process the incoming data (in.buf) of length
- * 'in.len', and set 'in.num_bytes', which is how many bytes of POST
- * data was processed and can be discarded by SHTTPD.
- * 5. If callback allocates arg->state, to keep state, it must deallocate it
- * at the end of coonection SHTTPD_CONNECTION_ERROR or SHTTPD_END_OF_OUTPUT
- * 6. If callback function wants to suspend until some event, it must store
- * arg->priv pointer elsewhere, set SHTTPD_SUSPEND flag and return. When
- * the event happens, user code should call shttpd_wakeup(priv).
- * It is safe to call shttpd_wakeup() from any thread. User code must
- * not call shttpd_wakeup once the connection is closed.
- */
-typedef void (*shttpd_callback_t)(struct shttpd_arg *);
-
-/*
- * shttpd_init Initialize shttpd context
- * shttpd_fini Dealocate the context, close all connections
- * shttpd_set_option Set new value for option
- * shttpd_register_uri Setup the callback function for specified URL
- * shttpd_poll Do connections processing
- * shttpd_version return string with SHTTPD version
- * shttpd_get_var Fetch POST/GET variable value by name. Return value len
- * shttpd_get_header return value of the specified HTTP header
- * shttpd_get_env return values for the following pseudo-variables:
- "REQUEST_METHOD", "REQUEST_URI",
- * "REMOTE_USER" and "REMOTE_ADDR"
- * shttpd_printf helper function to output data
- * shttpd_handle_error register custom HTTP error handler
- * shttpd_wakeup clear SHTTPD_SUSPEND state for the connection
- */
-
-struct shttpd_ctx;
-
-struct shttpd_ctx *shttpd_init(int argc, char *argv[]);
-int shttpd_set_option(struct shttpd_ctx *, const char *opt, const char *val);
-void shttpd_fini(struct shttpd_ctx *);
-void shttpd_register_uri(struct shttpd_ctx *ctx, const char *uri,
- shttpd_callback_t callback, void *const user_data);
-void shttpd_poll(struct shttpd_ctx *, int milliseconds);
-const char *shttpd_version(void);
-int shttpd_get_var(const char *var, const char *buf, int buf_len,
- char *value, int value_len);
-const char *shttpd_get_header(struct shttpd_arg *, const char *header_name);
-const char *shttpd_get_env(struct shttpd_arg *, const char *name);
-void shttpd_get_http_version(struct shttpd_arg *,
- unsigned long *major, unsigned long *minor);
-size_t shttpd_printf(struct shttpd_arg *, const char *fmt, ...);
-void shttpd_handle_error(struct shttpd_ctx *ctx, int status,
- shttpd_callback_t func, void *const data);
-void shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
- shttpd_callback_t func, void *const user_data);
-void shttpd_wakeup(const void *priv);
-int shttpd_join(struct shttpd_ctx *, fd_set *, fd_set *, int *max_fd);
-int shttpd_socketpair(int sp[2]);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* SHTTPD_HEADER_INCLUDED */
diff --git a/vendor/shttpd/ssl.h b/vendor/shttpd/ssl.h
deleted file mode 100644
index 5aeae4a..0000000
--- a/vendor/shttpd/ssl.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-/*
- * Snatched from OpenSSL includes. I put the prototypes here to be independent
- * from the OpenSSL source installation. Having this, shttpd + SSL can be
- * built on any system with binary SSL libraries installed.
- */
-
-typedef struct ssl_st SSL;
-typedef struct ssl_method_st SSL_METHOD;
-typedef struct ssl_ctx_st SSL_CTX;
-
-#define SSL_ERROR_WANT_READ 2
-#define SSL_ERROR_WANT_WRITE 3
-#define SSL_FILETYPE_PEM 1
-
-/*
- * Dynamically loaded SSL functionality
- */
-struct ssl_func {
- const char *name; /* SSL function name */
- union variant ptr; /* Function pointer */
-};
-
-extern struct ssl_func ssl_sw[];
-
-#define FUNC(x) ssl_sw[x].ptr.v_func
-
-#define SSL_free(x) (* (void (*)(SSL *)) FUNC(0))(x)
-#define SSL_accept(x) (* (int (*)(SSL *)) FUNC(1))(x)
-#define SSL_connect(x) (* (int (*)(SSL *)) FUNC(2))(x)
-#define SSL_read(x,y,z) (* (int (*)(SSL *, void *, int)) FUNC(3))((x),(y),(z))
-#define SSL_write(x,y,z) \
- (* (int (*)(SSL *, const void *,int)) FUNC(4))((x), (y), (z))
-#define SSL_get_error(x,y)(* (int (*)(SSL *, int)) FUNC(5))((x), (y))
-#define SSL_set_fd(x,y) (* (int (*)(SSL *, int)) FUNC(6))((x), (y))
-#define SSL_new(x) (* (SSL * (*)(SSL_CTX *)) FUNC(7))(x)
-#define SSL_CTX_new(x) (* (SSL_CTX * (*)(SSL_METHOD *)) FUNC(8))(x)
-#define SSLv23_server_method() (* (SSL_METHOD * (*)(void)) FUNC(9))()
-#define SSL_library_init() (* (int (*)(void)) FUNC(10))()
-#define SSL_CTX_use_PrivateKey_file(x,y,z) (* (int (*)(SSL_CTX *, \
- const char *, int)) FUNC(11))((x), (y), (z))
-#define SSL_CTX_use_certificate_file(x,y,z) (* (int (*)(SSL_CTX *, \
- const char *, int)) FUNC(12))((x), (y), (z))
diff --git a/vendor/shttpd/standalone.c b/vendor/shttpd/standalone.c
deleted file mode 100644
index 89ba661..0000000
--- a/vendor/shttpd/standalone.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-static int exit_flag; /* Program termination flag */
-
-static void
-signal_handler(int sig_num)
-{
- switch (sig_num) {
-#ifndef _WIN32
- case SIGCHLD:
- while (waitpid(-1, &sig_num, WNOHANG) > 0) ;
- break;
-#endif /* !_WIN32 */
- default:
- exit_flag = sig_num;
- break;
- }
-}
-
-int
-main(int argc, char *argv[])
-{
- struct shttpd_ctx *ctx;
-
-#if !defined(NO_AUTH)
- if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') {
- if (argc != 6)
- _shttpd_usage(argv[0]);
- exit(_shttpd_edit_passwords(argv[2],argv[3],argv[4],argv[5]));
- }
-#endif /* NO_AUTH */
-
- if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
- _shttpd_usage(argv[0]);
-
-#if defined(_WIN32)
- try_to_run_as_nt_service();
-#endif /* _WIN32 */
-
-#ifndef _WIN32
- (void) signal(SIGCHLD, signal_handler);
- (void) signal(SIGPIPE, SIG_IGN);
-#endif /* _WIN32 */
-
- (void) signal(SIGTERM, signal_handler);
- (void) signal(SIGINT, signal_handler);
-
- if ((ctx = shttpd_init(argc, argv)) == NULL)
- _shttpd_elog(E_FATAL, NULL, "%s",
- "Cannot initialize SHTTPD context");
-
- _shttpd_elog(E_LOG, NULL, "shttpd %s started on port(s) %s, serving %s",
- VERSION, ctx->options[OPT_PORTS], ctx->options[OPT_ROOT]);
-
- while (exit_flag == 0)
- shttpd_poll(ctx, 10 * 1000);
-
- _shttpd_elog(E_LOG, NULL, "Exit on signal %d", exit_flag);
- shttpd_fini(ctx);
-
- return (EXIT_SUCCESS);
-}
diff --git a/vendor/shttpd/std_includes.h b/vendor/shttpd/std_includes.h
deleted file mode 100644
index 4bf1ea7..0000000
--- a/vendor/shttpd/std_includes.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#ifndef STD_HEADERS_INCLUDED
-#define STD_HEADERS_INCLUDED
-
-#ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-#endif /* _WIN32_WCE */
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdio.h>
-
-#if defined(_WIN32) /* Windows specific */
-#include "compat_win32.h"
-#elif defined(__rtems__) /* RTEMS specific */
-#include "compat_rtems.h"
-#else /* UNIX specific */
-#include "compat_unix.h"
-#endif /* _WIN32 */
-
-#endif /* STD_HEADERS_INCLUDED */
diff --git a/vendor/shttpd/string.c b/vendor/shttpd/string.c
deleted file mode 100644
index a383cf8..0000000
--- a/vendor/shttpd/string.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok(a)gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
-
-#include "defs.h"
-
-void
-_shttpd_strlcpy(register char *dst, register const char *src, size_t n)
-{
- for (; *src != '\0' && n > 1; n--)
- *dst++ = *src++;
- *dst = '\0';
-}
-
-int
-_shttpd_strncasecmp(const char *str1, const char *str2, size_t len)
-{
- register const unsigned char *s1 = (unsigned char *) str1,
- *s2 = (unsigned char *) str2, *e;
- int ret;
-
- for (e = s1 + len - 1; s1 < e && *s1 != '\0' && *s2 != '\0' &&
- tolower(*s1) == tolower(*s2); s1++, s2++) ;
- ret = tolower(*s1) - tolower(*s2);
-
- return (ret);
-}
-
-char *
-_shttpd_strndup(const char *ptr, size_t len)
-{
- char *p;
-
- if ((p = malloc(len + 1)) != NULL)
- _shttpd_strlcpy(p, ptr, len + 1);
-
- return (p);
-
-}
-
-char *
-_shttpd_strdup(const char *str)
-{
- return (_shttpd_strndup(str, strlen(str)));
-}
-
-/*
- * Sane snprintf(). Acts like snprintf(), but never return -1 or the
- * value bigger than supplied buffer.
- * Thanks Adam Zeldis to pointing snprintf()-caused vulnerability
- * in his audit report.
- */
-int
-_shttpd_snprintf(char *buf, size_t buflen, const char *fmt, ...)
-{
- va_list ap;
- int n;
-
- if (buflen == 0)
- return (0);
-
- va_start(ap, fmt);
- n = vsnprintf(buf, buflen, fmt, ap);
- va_end(ap);
-
- if (n < 0 || (size_t) n >= buflen)
- n = buflen - 1;
- buf[n] = '\0';
-
- return (n);
-}
-
-/*
- * Verify that given file has certain extension
- */
-int
-_shttpd_match_extension(const char *path, const char *ext_list)
-{
- size_t len, path_len;
-
- path_len = strlen(path);
-
- FOR_EACH_WORD_IN_LIST(ext_list, len)
- if (len < path_len && path[path_len - len - 1] == '.' &&
- !_shttpd_strncasecmp(path + path_len - len, ext_list, len))
- return (TRUE);
-
- return (FALSE);
-}
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
![](https://seccdn.libravatar.org/avatar/bbcc248607dd5cc3db5ea99581004c2c.jpg?s=120&d=mm&r=g)
05 Feb '09
ref: refs/heads/master
commit 2b092bd3b11a2243ea0fce4034ef5d8ab6829a24
Author: Duncan Mac-Vicar P <dmacvicar(a)suse.de>
Date: Thu Feb 5 15:49:25 2009 +0100
finally testcases pass.
add ruby to build requires, as we are using webrick for webserver
testcases for now
---
libzypp.spec.cmake | 3 ++
tests/lib/WebServer.cc | 50 ++++++++++---------------------------------
tests/zypp/Fetcher_test.cc | 6 ++--
3 files changed, 18 insertions(+), 41 deletions(-)
diff --git a/libzypp.spec.cmake b/libzypp.spec.cmake
index 3e28637..159c123 100644
--- a/libzypp.spec.cmake
+++ b/libzypp.spec.cmake
@@ -28,6 +28,9 @@ BuildRequires: cmake
BuildRequires: libsatsolver-devel >= 0.13.0 openssl-devel
BuildRequires: boost-devel curl-devel dejagnu doxygen gcc-c++ gettext-devel graphviz hal-devel libxml2-devel
+# required for testsuite, webrick
+BuildRequires: ruby
+
%if 0%{?suse_version}
BuildRequires: libexpat-devel
%else
diff --git a/tests/lib/WebServer.cc b/tests/lib/WebServer.cc
index 4d05eb8..426b08e 100644
--- a/tests/lib/WebServer.cc
+++ b/tests/lib/WebServer.cc
@@ -1,6 +1,4 @@
-//#include "zypp/ZYpp.h"
-
#include <sstream>
#include <string>
#include "boost/bind.hpp"
@@ -16,7 +14,7 @@
using namespace zypp;
using namespace std;
-#define WEBRICK 0
+#define WEBRICK 1
class WebServer::Impl
{
@@ -81,18 +79,8 @@ public:
_stopped = false;
- while ( _stop );
+ while ( ! _stop );
- /*
- for(line = prog.receiveLine();
- !line.empty();
- line = prog.receiveLine() )
- {
- strlog << line;
- if ( _stop )
- break;
- }
- */
MIL << "Thread end requested" << endl;
//prog.close();
if ( prog.running() )
@@ -133,34 +121,29 @@ class WebServerMongooseImpl : public WebServer::Impl
public:
WebServerMongooseImpl(const Pathname &root, unsigned int port)
: _ctx(0L), _docroot(root)
- , _port(port), _stop(false)
+ , _port(port)
, _stopped(true)
{
}
~WebServerMongooseImpl()
{
+ MIL << "Destroying web server" << endl;
+
if ( ! _stopped )
stop();
}
- virtual void worker_thread()
+ virtual void start()
{
+ MIL << "Starting shttpd (mongoose)" << endl;
_log.clear();
_ctx = mg_start();
if ( ! mg_set_option(_ctx, "ports", str::form("%d", _port).c_str()) )
ZYPP_THROW(Exception("Failed to set port"));
mg_set_option(_ctx, "root", _docroot.c_str());
- stringstream strlog(_log);
-
- while ( !_stop )
- {
- // loop
- }
- MIL << "Thread end requested, shutting down shttpd" << endl;
- mg_stop(_ctx);
- _ctx = 0;
+ _stopped = false;
}
virtual string log() const
@@ -170,25 +153,16 @@ public:
virtual void stop()
{
- MIL << "Waiting for shttpd thread to finish" << endl;
- _stop = true;
- _thrd->join();
- MIL << "shttpd thread to finished" << endl;
- _thrd.reset();
+ MIL << "Stopping shttpd" << endl;
+ mg_stop(_ctx);
+ MIL << "shttpd finished" << endl;
+ _ctx = 0;
_stopped = true;
}
- virtual void start()
- {
- MIL << "Starting shttpd (mongoose) thread" << endl;
- _thrd.reset( new boost::thread( boost::bind(&WebServerMongooseImpl::worker_thread, this) ) );
- }
-
mg_context *_ctx;
zypp::Pathname _docroot;
unsigned int _port;
- zypp::shared_ptr<boost::thread> _thrd;
- bool _stop;
bool _stopped;
std::string _log;
};
diff --git a/tests/zypp/Fetcher_test.cc b/tests/zypp/Fetcher_test.cc
index a00ece2..c663c11 100644
--- a/tests/zypp/Fetcher_test.cc
+++ b/tests/zypp/Fetcher_test.cc
@@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE(enqueuedir_http)
WebServer web((Pathname(TESTS_SRC_DIR) + "/zypp/data/Fetcher/remote-site").c_str(), 10001);
web.start();
- MediaSetAccess media( Url("http://127.0.0.1:10001"), "/" );
+ MediaSetAccess media( Url("http://localhost:10001"), "/" );
Fetcher fetcher;
filesystem::TmpDir dest;
@@ -355,10 +355,10 @@ BOOST_AUTO_TEST_CASE(enqueuedir_http_broken)
// add the key as trusted
//getZYpp()->keyRing()->importKey(PublicKey(DATADIR + "/complexdir/subdir1/SHA1SUMS.key"), true);
- WebServer web((Pathname(TESTS_SRC_DIR) + "/zypp/data/Fetcher/remote-site").c_str() , 10002 );
+ WebServer web((Pathname(TESTS_SRC_DIR) + "/zypp/data/Fetcher/remote-site").c_str() , 10001 );
web.start();
- MediaSetAccess media( Url("http://127.0.0.1:10002"), "/" );
+ MediaSetAccess media( Url("http://localhost:10001"), "/" );
Fetcher fetcher;
filesystem::TmpDir dest;
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
![](https://seccdn.libravatar.org/avatar/03f46662129c78729420d160bdff6dd0.jpg?s=120&d=mm&r=g)
[zypp-commit] <dialogsolver> SuSE-Code-11-Branch : update translations
by Stefan Schubert 05 Feb '09
by Stefan Schubert 05 Feb '09
05 Feb '09
ref: refs/heads/SuSE-Code-11-Branch
commit 338d0883079a107e3ae8a114e883a9b920af9f8a
Author: Stefan Schubert <schubi(a)suse.de>
Date: Thu Feb 5 15:18:03 2009 +0100
update translations
---
VERSION.cmake | 2 +-
package/libqdialogsolver1.changes | 7 +++++++
2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/VERSION.cmake b/VERSION.cmake
index 69972f9..bca887d 100644
--- a/VERSION.cmake
+++ b/VERSION.cmake
@@ -1,3 +1,3 @@
SET(VERSION_MAJOR "1")
SET(VERSION_MINOR "2")
-SET(VERSION_PATCH "8")
+SET(VERSION_PATCH "9")
diff --git a/package/libqdialogsolver1.changes b/package/libqdialogsolver1.changes
index bd01c20..97c8c32 100644
--- a/package/libqdialogsolver1.changes
+++ b/package/libqdialogsolver1.changes
@@ -1,4 +1,11 @@
-------------------------------------------------------------------
+Thu Feb 5 15:17:21 CET 2009 - schubi(a)suse.de
+
+- Update translations
+- version 1.2.9
+
+
+-------------------------------------------------------------------
Mon Jan 26 16:24:16 CET 2009 - schubi(a)suse.de
- Update translations
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0
ref: refs/heads/master
commit 338d0883079a107e3ae8a114e883a9b920af9f8a
Author: Stefan Schubert <schubi(a)suse.de>
Date: Thu Feb 5 15:18:03 2009 +0100
update translations
---
VERSION.cmake | 2 +-
package/libqdialogsolver1.changes | 7 +++++++
2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/VERSION.cmake b/VERSION.cmake
index 69972f9..bca887d 100644
--- a/VERSION.cmake
+++ b/VERSION.cmake
@@ -1,3 +1,3 @@
SET(VERSION_MAJOR "1")
SET(VERSION_MINOR "2")
-SET(VERSION_PATCH "8")
+SET(VERSION_PATCH "9")
diff --git a/package/libqdialogsolver1.changes b/package/libqdialogsolver1.changes
index bd01c20..97c8c32 100644
--- a/package/libqdialogsolver1.changes
+++ b/package/libqdialogsolver1.changes
@@ -1,4 +1,11 @@
-------------------------------------------------------------------
+Thu Feb 5 15:17:21 CET 2009 - schubi(a)suse.de
+
+- Update translations
+- version 1.2.9
+
+
+-------------------------------------------------------------------
Mon Jan 26 16:24:16 CET 2009 - schubi(a)suse.de
- Update translations
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org
1
0