summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--cfws.sln31
-rw-r--r--cfws.vcxproj165
-rw-r--r--cfws.vcxproj.filters48
-rw-r--r--cfws.vcxproj.user6
-rw-r--r--src/ClientConnection.cpp23
-rw-r--r--src/ServerConnection.cpp26
-rw-r--r--src/main.cpp18
8 files changed, 308 insertions, 11 deletions
diff --git a/.gitignore b/.gitignore
index 3bfe699..468ae6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
# Ignore IDE and editor project files
.vscode
+.vs
# Ignore build output
+build/
cfws
*.o
diff --git a/cfws.sln b/cfws.sln
new file mode 100644
index 0000000..568c33e
--- /dev/null
+++ b/cfws.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33516.290
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cfws", "cfws.vcxproj", "{FAFC8784-5A23-416E-9384-74A9F9D53F0D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FAFC8784-5A23-416E-9384-74A9F9D53F0D}.Debug|x64.ActiveCfg = Debug|x64
+ {FAFC8784-5A23-416E-9384-74A9F9D53F0D}.Debug|x64.Build.0 = Debug|x64
+ {FAFC8784-5A23-416E-9384-74A9F9D53F0D}.Debug|x86.ActiveCfg = Debug|Win32
+ {FAFC8784-5A23-416E-9384-74A9F9D53F0D}.Debug|x86.Build.0 = Debug|Win32
+ {FAFC8784-5A23-416E-9384-74A9F9D53F0D}.Release|x64.ActiveCfg = Release|x64
+ {FAFC8784-5A23-416E-9384-74A9F9D53F0D}.Release|x64.Build.0 = Release|x64
+ {FAFC8784-5A23-416E-9384-74A9F9D53F0D}.Release|x86.ActiveCfg = Release|Win32
+ {FAFC8784-5A23-416E-9384-74A9F9D53F0D}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {7D5025E0-100E-4F05-97C2-24FFFD3E487D}
+ EndGlobalSection
+EndGlobal
diff --git a/cfws.vcxproj b/cfws.vcxproj
new file mode 100644
index 0000000..e10f31a
--- /dev/null
+++ b/cfws.vcxproj
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectGuid>{fafc8784-5a23-416e-9384-74a9f9d53f0d}</ProjectGuid>
+ <RootNamespace>cfws</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</OutDir>
+ <IntDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</OutDir>
+ <IntDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <OutDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</OutDir>
+ <IntDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <OutDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</OutDir>
+ <IntDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <LanguageStandard>stdcpp17</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <LanguageStandard>stdcpp17</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <LanguageStandard>stdcpp17</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <LanguageStandard>stdcpp17</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="src\ClientConnection.h" />
+ <ClInclude Include="src\HttpRequest.h" />
+ <ClInclude Include="src\HttpResponse.h" />
+ <ClInclude Include="src\ServerConnection.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\ClientConnection.cpp" />
+ <ClCompile Include="src\HttpRequest.cpp" />
+ <ClCompile Include="src\HttpResponse.cpp" />
+ <ClCompile Include="src\main.cpp" />
+ <ClCompile Include="src\ServerConnection.cpp" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/cfws.vcxproj.filters b/cfws.vcxproj.filters
new file mode 100644
index 0000000..bd4ed7f
--- /dev/null
+++ b/cfws.vcxproj.filters
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\ServerConnection.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\ClientConnection.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\HttpRequest.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\HttpResponse.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\ClientConnection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\HttpRequest.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\HttpResponse.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\ServerConnection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/cfws.vcxproj.user b/cfws.vcxproj.user
new file mode 100644
index 0000000..dc63f8a
--- /dev/null
+++ b/cfws.vcxproj.user
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ShowAllFiles>false</ShowAllFiles>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/ClientConnection.cpp b/src/ClientConnection.cpp
index c434212..e8e6692 100644
--- a/src/ClientConnection.cpp
+++ b/src/ClientConnection.cpp
@@ -3,7 +3,13 @@
#include <cstring>
#include <iostream>
#include <sstream>
-#include <unistd.h>
+
+#ifdef _WIN32
+ #include <winsock2.h>
+ #pragma comment(lib, "ws2_32.lib")
+#else
+ #include <unistd.h>
+#endif
ClientConnection::ClientConnection(int socket)
: m_socket_fd(socket)
@@ -19,7 +25,12 @@ HttpRequest ClientConnection::read_request() const
int n = 0;
memset(buffer, 0, BUFFER_SIZE);
- while ((n = read(m_socket_fd, buffer, BUFFER_SIZE - 1)) > 0) {
+#ifdef _WIN32
+ n = recv(m_socket_fd, buffer, BUFFER_SIZE - 1, 0);
+#else
+ n = read(m_socket_fd, buffer, BUFFER_SIZE - 1);
+#endif
+ while (n > 0) {
if (buffer[n - 1] == '\n')
break;
@@ -35,7 +46,11 @@ bool ClientConnection::send(const HttpResponse& response) const
return false;
std::string result = response.to_string();
+#ifdef _WIN32
+ ::send(m_socket_fd, result.c_str(), result.length(), 0);
+#else
write(m_socket_fd, result.c_str(), result.length());
+#endif
return true;
}
@@ -43,5 +58,9 @@ bool ClientConnection::send(const HttpResponse& response) const
void ClientConnection::close_connection()
{
m_is_open = false;
+#ifdef _WIN32
+ closesocket(m_socket_fd);
+#else
close(m_socket_fd);
+#endif
}
diff --git a/src/ServerConnection.cpp b/src/ServerConnection.cpp
index 64692b6..0a47dc3 100644
--- a/src/ServerConnection.cpp
+++ b/src/ServerConnection.cpp
@@ -1,13 +1,17 @@
#include "ServerConnection.h"
-#include <arpa/inet.h>
-#include <csignal>
-#include <netdb.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/time.h>
#include <sys/types.h>
-#include <unistd.h>
+
+#ifdef _WIN32
+ #include <winsock2.h>
+ #pragma comment(lib, "ws2_32.lib")
+#else
+ #include <arpa/inet.h>
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+ #include <sys/time.h>
+ #include <unistd.h>
+#endif
#include "ClientConnection.h"
@@ -19,14 +23,22 @@ static void error_and_die(const char* message)
ServerConnection::ServerConnection(int port)
{
+#ifdef _WIN32
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
+ error_and_die("Failed to initialize Winsock");
+#endif
+
sockaddr_in address {};
int socket_options = 1;
if ((m_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error_and_die("Failed to create socket");
+#ifndef _WIN32
if (setsockopt(m_socket_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &socket_options, sizeof(socket_options)) != 0)
error_and_die("setsockopt");
+#endif
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
diff --git a/src/main.cpp b/src/main.cpp
index c0c9bb3..4937f0d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,11 +1,15 @@
+#ifndef _WIN32
#include <getopt.h>
+#endif
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
+#ifndef _WIN32
#include "CGIScript.h"
+#endif
#include "ClientConnection.h"
#include "HttpRequest.h"
#include "HttpResponse.h"
@@ -66,6 +70,7 @@ static HttpResponse serve_from_filesystem(const HttpRequest& request)
return response;
}
+#ifndef _WIN32
static HttpResponse serve_from_cgi(const std::string& script_path, const HttpRequest& request)
{
HttpResponse response;
@@ -99,11 +104,14 @@ static HttpResponse serve_from_cgi(const std::string& script_path, const HttpReq
response.add_headers_and_content(script.read_output());
return response;
}
+#endif
+#ifndef _WIN32
static option long_options[] = {
{ "cgi", required_argument, nullptr, 'c' },
{ "port", required_argument, nullptr, 'p' },
};
+#endif
int main(int argc, char** argv)
{
@@ -111,6 +119,8 @@ int main(int argc, char** argv)
bool in_cgi_mode = false;
std::string cgi_program_name;
+ // TODO: getopt.h is not available on Windows, so this part needs to be rewritten.
+#ifndef _WIN32
int c = 0;
int option_index = 0;
while ((c = getopt_long(argc, argv, "c:p:", long_options, &option_index)) != -1) {
@@ -135,6 +145,7 @@ int main(int argc, char** argv)
// script before attempting to start the server.
if (in_cgi_mode)
CGIScript::validate_path(cgi_program_name);
+#endif
ServerConnection server(port);
std::cout << "Serving a " << (in_cgi_mode ? "CGI script" : "directory") << " on port " << port << std::endl;
@@ -144,11 +155,14 @@ int main(int argc, char** argv)
HttpRequest request = client.read_request();
HttpResponse response;
+ // TODO: Support running CGI executables on Windows
+#ifndef _WIN32
if (in_cgi_mode) {
response = serve_from_cgi(cgi_program_name, request);
- } else {
+ } else
+#endif
response = serve_from_filesystem(request);
- }
+
client.send(response);
client.close_connection();