Skip to content

Commit 82315df

Browse files
committed
Http: Remove dependency on Time library
1 parent b449809 commit 82315df

File tree

3 files changed

+75
-32
lines changed

3 files changed

+75
-32
lines changed

Documentation/Libraries/Http.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
[SaneCppHttp.h](https://github.com/Pagghiu/SaneCppLibraries/releases/latest/download/SaneCppHttp.h) is a library implementing a hand-written http 1.1 parser, client and server.
88

99
# Dependencies
10-
- Dependencies: [Async](@ref library_async), [Containers](@ref library_containers), [Time](@ref library_time)
11-
- All dependencies: [Async](@ref library_async), [Containers](@ref library_containers), [File](@ref library_file), [FileSystem](@ref library_file_system), [Foundation](@ref library_foundation), [Memory](@ref library_memory), [Socket](@ref library_socket), [Threading](@ref library_threading), [Time](@ref library_time)
10+
- Dependencies: [Async](@ref library_async), [Containers](@ref library_containers)
11+
- All dependencies: [Async](@ref library_async), [Containers](@ref library_containers), [File](@ref library_file), [FileSystem](@ref library_file_system), [Foundation](@ref library_foundation), [Memory](@ref library_memory), [Socket](@ref library_socket), [Threading](@ref library_threading)
1212

1313
![Dependency Graph](Http.svg)
1414

Libraries/Http/HttpWebServer.cpp

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@
22
// SPDX-License-Identifier: MIT
33
#include "HttpWebServer.h"
44
#include "../FileSystem/FileSystem.h"
5-
#include "../Time/Time.h"
65
#include "Internal/HttpStringIterator.h"
76
#include <stdio.h>
7+
#include <time.h>
8+
#if SC_PLATFORM_WINDOWS
9+
#define WIN32_LEAN_AND_MEAN
10+
#include <Windows.h>
11+
#include <sys/timeb.h>
12+
#else
13+
#include <math.h>
14+
#endif
815

916
struct SC::HttpWebServer::Internal
1017
{
11-
static Result writeGMTHeaderTime(StringSpan headerName, HttpResponse& response,
12-
const Time::Absolute::ParseResult& local);
18+
static Result writeGMTHeaderTime(StringSpan headerName, HttpResponse& response, int64_t millisecondsSinceEpoch);
1319
static Result readFile(StringSpan initialDirectory, HttpRequest& request, HttpResponse& response);
20+
static Result formatHttpDate(int64_t millisecondsSinceEpoch, char* buffer, size_t bufferSize, size_t& outLength);
1421

22+
static int64_t getCurrentTimeMilliseconds();
1523
static StringSpan getContentType(const StringSpan extension);
1624
};
1725

@@ -58,32 +66,13 @@ SC::Result SC::HttpWebServer::Internal::readFile(StringSpan directory, HttpReque
5866
SC_TRY(response.addHeader("Connection", "Closed"));
5967
SC_TRY(response.addHeader("Content-Type", Internal::getContentType(extension)));
6068
SC_TRY(response.addHeader("Server", "SC"));
61-
Time::Absolute::ParseResult local;
62-
SC_TRY(Time::Realtime::now().parseUTC(local));
63-
SC_TRY(Internal::writeGMTHeaderTime("Date", response, local));
64-
SC_TRY(Time::Realtime(fileStat.modifiedTime).parseUTC(local));
65-
SC_TRY(Internal::writeGMTHeaderTime("Last-Modified", response, local));
69+
SC_TRY(Internal::writeGMTHeaderTime("Date", response, Internal::getCurrentTimeMilliseconds()));
70+
SC_TRY(Internal::writeGMTHeaderTime("Last-Modified", response, fileStat.modifiedTime.milliseconds));
6671
SC_TRY(response.end(data.toSpanConst()));
6772
}
6873
return Result(true);
6974
}
7075

71-
SC::Result SC::HttpWebServer::Internal::writeGMTHeaderTime(StringSpan headerName, HttpResponse& response,
72-
const Time::Absolute::ParseResult& local)
73-
{
74-
char bufferData[128];
75-
size_t len = static_cast<size_t>(::snprintf(bufferData, sizeof(bufferData), "%s, %02u %s %04u %02u:%02u:%02u GMT",
76-
local.getDay(), local.dayOfMonth, local.getMonth(), local.year,
77-
local.hour, local.minutes, local.seconds));
78-
if (len == 0 or len >= sizeof(bufferData))
79-
{
80-
return Result::Error("Failed to format time");
81-
}
82-
83-
SC_TRY(response.addHeader(headerName, {{bufferData, len}, true, StringEncoding::Ascii}));
84-
return Result(true);
85-
}
86-
8776
SC::StringSpan SC::HttpWebServer::Internal::getContentType(const StringSpan extension)
8877
{
8978
if (extension == "htm" or extension == "html")
@@ -108,3 +97,60 @@ SC::StringSpan SC::HttpWebServer::Internal::getContentType(const StringSpan exte
10897
}
10998
return "text/html";
11099
}
100+
101+
SC::int64_t SC::HttpWebServer::Internal::getCurrentTimeMilliseconds()
102+
{
103+
#if SC_PLATFORM_WINDOWS
104+
struct _timeb t;
105+
_ftime_s(&t);
106+
return static_cast<int64_t>(t.time) * 1000 + t.millitm;
107+
#else
108+
struct timespec nowTimeSpec;
109+
clock_gettime(CLOCK_REALTIME, &nowTimeSpec);
110+
return static_cast<int64_t>(round(nowTimeSpec.tv_nsec / 1.0e6) + nowTimeSpec.tv_sec * 1000);
111+
#endif
112+
}
113+
114+
SC::Result SC::HttpWebServer::Internal::formatHttpDate(int64_t millisecondsSinceEpoch, char* buffer, size_t bufferSize,
115+
size_t& outLength)
116+
{
117+
const time_t seconds = static_cast<time_t>(millisecondsSinceEpoch / 1000);
118+
struct tm parsedTm;
119+
#if SC_PLATFORM_WINDOWS
120+
if (_gmtime64_s(&parsedTm, &seconds) != 0)
121+
{
122+
return Result::Error("Failed to convert time");
123+
}
124+
#else
125+
if (gmtime_r(&seconds, &parsedTm) == nullptr)
126+
{
127+
return Result::Error("Failed to convert time");
128+
}
129+
#endif
130+
131+
// Format as HTTP date: "Wed, 21 Oct 2015 07:28:00 GMT"
132+
const char* days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
133+
const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
134+
135+
outLength = static_cast<size_t>(
136+
snprintf(buffer, bufferSize, "%s, %02d %s %04d %02d:%02d:%02d GMT", days[parsedTm.tm_wday], parsedTm.tm_mday,
137+
months[parsedTm.tm_mon], parsedTm.tm_year + 1900, parsedTm.tm_hour, parsedTm.tm_min, parsedTm.tm_sec));
138+
139+
if (outLength == 0 || outLength >= bufferSize)
140+
{
141+
return Result::Error("Failed to format time");
142+
}
143+
144+
return Result(true);
145+
}
146+
147+
SC::Result SC::HttpWebServer::Internal::writeGMTHeaderTime(StringSpan headerName, HttpResponse& response,
148+
int64_t millisecondsSinceEpoch)
149+
{
150+
char bufferData[128];
151+
size_t len;
152+
SC_TRY(formatHttpDate(millisecondsSinceEpoch, bufferData, sizeof(bufferData), len));
153+
154+
SC_TRY(response.addHeader(headerName, {{bufferData, len}, true, StringEncoding::Ascii}));
155+
return Result(true);
156+
}

Support/Dependencies/Dependencies.json

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,11 @@
155155
"FileSystem",
156156
"Foundation",
157157
"Memory",
158-
"Socket",
159-
"Time"
158+
"Socket"
160159
],
161160
"minimal_dependencies": [
162161
"Async",
163-
"Containers",
164-
"Time"
162+
"Containers"
165163
],
166164
"all_dependencies": [
167165
"Async",
@@ -171,8 +169,7 @@
171169
"Foundation",
172170
"Memory",
173171
"Socket",
174-
"Threading",
175-
"Time"
172+
"Threading"
176173
]
177174
},
178175
"Memory": {

0 commit comments

Comments
 (0)