Skip to content

Commit 902bf3d

Browse files
Yuji HiroseYuji Hirose
authored andcommitted
Removed 'FILE' I/O, use socket directly.
1 parent d0759eb commit 902bf3d

File tree

1 file changed

+102
-62
lines changed

1 file changed

+102
-62
lines changed

httplib.h

Lines changed: 102 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ class Server {
114114
private:
115115
typedef std::vector<std::pair<std::regex, Handler>> Handlers;
116116

117-
void process_request(FILE* fp_read, FILE* fp_write);
118-
bool read_request_line(FILE* fp, Request& req);
117+
void process_request(socket_t sock);
118+
bool read_request_line(socket_t sock, Request& req);
119119
bool routing(Request& req, Response& res);
120120
bool handle_file_request(Request& req, Response& res);
121121
bool dispatch_request(Request& req, Response& res, Handlers& handlers);
@@ -140,7 +140,7 @@ class Client {
140140
bool send(const Request& req, Response& res);
141141

142142
private:
143-
bool read_response_line(FILE* fp, Response& res);
143+
bool read_response_line(socket_t sock, Response& res);
144144

145145
const std::string host_;
146146
const int port_;
@@ -168,35 +168,59 @@ void split(const char* b, const char* e, char d, Fn fn)
168168
}
169169
}
170170

171-
template <typename T>
172-
inline bool read_and_close_socket(socket_t sock, T callback)
171+
inline int socket_read(socket_t sock, char* ptr, size_t size)
173172
{
174-
FILE* fp_read;
175-
FILE* fp_write;
173+
return recv(sock, ptr, size, 0);
174+
}
176175

177-
#ifdef _MSC_VER
178-
fp_read = _fdopen(_open_osfhandle(sock, _O_RDONLY), "rb");
179-
fp_write = _fdopen(_open_osfhandle(sock, _O_WRONLY), "wb");
180-
#else
181-
fp_read = fdopen(sock, "rb");
182-
fp_write = fdopen(sock, "wb");
183-
#endif
176+
inline int socket_write(socket_t sock, const char* ptr, size_t size = -1)
177+
{
178+
if (size == -1) {
179+
size = strlen(ptr);
180+
}
181+
return send(sock, ptr, size, 0);
182+
}
184183

185-
auto ret = callback(fp_read, fp_write);
184+
inline bool socket_gets(socket_t sock, char* buf, int bufsiz)
185+
{
186+
// TODO: buffering for better performance
187+
size_t i = 0;
186188

187-
fclose(fp_read);
188-
fclose(fp_write);
189+
for (;;) {
190+
char byte;
191+
auto n = socket_read(sock, &byte, 1);
189192

190-
return ret;
193+
if (n < 1) {
194+
if (i == 0) {
195+
return false;
196+
} else {
197+
break;
198+
}
199+
}
200+
201+
buf[i++] = byte;
202+
203+
if (byte == '\n') {
204+
break;
205+
}
206+
}
207+
208+
buf[i] = '\0';
209+
return true;
191210
}
192211

193-
inline int shutdown_socket(socket_t sock)
212+
template <typename ...Args>
213+
inline void socket_printf(socket_t sock, const char* fmt, const Args& ...args)
194214
{
195-
#ifdef _MSC_VER
196-
return shutdown(sock, SD_BOTH);
197-
#else
198-
return shutdown(sock, SHUT_RDWR);
199-
#endif
215+
char buf[BUFSIZ];
216+
auto n = snprintf(buf, BUFSIZ, fmt, args...);
217+
if (n > 0) {
218+
if (n >= BUFSIZ) {
219+
// TODO: buffer size is not large enough...
220+
} else {
221+
socket_write(sock, buf, n);
222+
}
223+
}
200224
}
201225

202226
inline int close_socket(socket_t sock)
@@ -208,6 +232,23 @@ inline int close_socket(socket_t sock)
208232
#endif
209233
}
210234

235+
template <typename T>
236+
inline bool read_and_close_socket(socket_t sock, T callback)
237+
{
238+
auto ret = callback(sock);
239+
close_socket(sock);
240+
return ret;
241+
}
242+
243+
inline int shutdown_socket(socket_t sock)
244+
{
245+
#ifdef _MSC_VER
246+
return shutdown(sock, SD_BOTH);
247+
#else
248+
return shutdown(sock, SHUT_RDWR);
249+
#endif
250+
}
251+
211252
template <typename Fn>
212253
socket_t create_socket(const char* host, int port, Fn fn)
213254
{
@@ -297,7 +338,7 @@ inline void read_file(const std::string& path, std::string& out)
297338
fs.seekg(0, std::ios_base::end);
298339
auto size = fs.tellg();
299340
fs.seekg(0);
300-
out.resize(size);
341+
out.resize(static_cast<size_t>(size));
301342
fs.read(&out[0], size);
302343
}
303344

@@ -350,15 +391,15 @@ inline int get_header_value_int(const MultiMap& map, const char* key, int def)
350391
return def;
351392
}
352393

353-
inline bool read_headers(FILE* fp, MultiMap& headers)
394+
inline bool read_headers(socket_t sock, MultiMap& headers)
354395
{
355396
static std::regex re("(.+?): (.+?)\r\n");
356397

357398
const auto BUFSIZ_HEADER = 2048;
358399
char buf[BUFSIZ_HEADER];
359400

360401
for (;;) {
361-
if (!fgets(buf, BUFSIZ_HEADER, fp)) {
402+
if (!socket_gets(sock, buf, BUFSIZ_HEADER)) {
362403
return false;
363404
}
364405
if (!strcmp(buf, "\r\n")) {
@@ -376,43 +417,43 @@ inline bool read_headers(FILE* fp, MultiMap& headers)
376417
}
377418

378419
template <typename T>
379-
bool read_content(T& x, FILE* fp)
420+
bool read_content(socket_t sock, T& x)
380421
{
381422
auto len = get_header_value_int(x.headers, "Content-Length", 0);
382423
if (len) {
383424
x.body.assign(len, 0);
384-
if (!fread(&x.body[0], x.body.size(), 1, fp)) {
425+
if (!socket_read(sock, &x.body[0], x.body.size())) {
385426
return false;
386427
}
387428
}
388429
return true;
389430
}
390431

391432
template <typename T>
392-
inline void write_headers(FILE* fp, const T& res)
433+
inline void write_headers(socket_t sock, const T& res)
393434
{
394-
fprintf(fp, "Connection: close\r\n");
435+
socket_write(sock, "Connection: close\r\n");
395436

396437
for (const auto& x: res.headers) {
397438
if (x.first != "Content-Type" && x.first != "Content-Length") {
398-
fprintf(fp, "%s: %s\r\n", x.first.c_str(), x.second.c_str());
439+
socket_printf(sock, "%s: %s\r\n", x.first.c_str(), x.second.c_str());
399440
}
400441
}
401442

402443
auto t = get_header_value(res.headers, "Content-Type", "text/plain");
403-
fprintf(fp, "Content-Type: %s\r\n", t);
404-
fprintf(fp, "Content-Length: %ld\r\n", res.body.size());
405-
fprintf(fp, "\r\n");
444+
socket_printf(sock, "Content-Type: %s\r\n", t);
445+
socket_printf(sock, "Content-Length: %ld\r\n", res.body.size());
446+
socket_write(sock, "\r\n");
406447
}
407448

408-
inline void write_response(FILE* fp, const Request& req, const Response& res)
449+
inline void write_response(socket_t sock, const Request& req, const Response& res)
409450
{
410-
fprintf(fp, "HTTP/1.0 %d %s\r\n", res.status, status_message(res.status));
451+
socket_printf(sock, "HTTP/1.0 %d %s\r\n", res.status, status_message(res.status));
411452

412-
write_headers(fp, res);
453+
write_headers(sock, res);
413454

414455
if (!res.body.empty() && req.method != "HEAD") {
415-
fprintf(fp, "%s", res.body.c_str());
456+
socket_write(sock, res.body.c_str(), res.body.size());
416457
}
417458
}
418459

@@ -547,18 +588,19 @@ inline std::string decode_url(const std::string& s)
547588
return result;
548589
}
549590

550-
inline void write_request(FILE* fp, const Request& req)
591+
inline void write_request(socket_t sock, const Request& req)
551592
{
552593
auto url = encode_url(req.url);
553-
fprintf(fp, "%s %s HTTP/1.0\r\n", req.method.c_str(), url.c_str());
594+
socket_printf(sock, "%s %s HTTP/1.0\r\n", req.method.c_str(), url.c_str());
554595

555-
write_headers(fp, req);
596+
write_headers(sock, req);
556597

557598
if (!req.body.empty()) {
558599
if (req.has_header("application/x-www-form-urlencoded")) {
559-
fprintf(fp, "%s", encode_url(req.body).c_str());
600+
auto str = encode_url(req.body);
601+
socket_write(sock, str.c_str(), str.size());
560602
} else {
561-
fprintf(fp, "%s", req.body.c_str());
603+
socket_write(sock, req.body.c_str(), req.body.size());
562604
}
563605
}
564606
}
@@ -710,8 +752,8 @@ inline bool Server::listen(const char* host, int port)
710752
}
711753

712754
// TODO: should be async
713-
detail::read_and_close_socket(sock, [this](FILE* fp_read, FILE* fp_write) {
714-
process_request(fp_read, fp_write);
755+
detail::read_and_close_socket(sock, [this](socket_t sock) {
756+
process_request(sock);
715757
return true;
716758
});
717759
}
@@ -726,11 +768,11 @@ inline void Server::stop()
726768
svr_sock_ = -1;
727769
}
728770

729-
inline bool Server::read_request_line(FILE* fp, Request& req)
771+
inline bool Server::read_request_line(socket_t sock, Request& req)
730772
{
731773
const auto BUFSIZ_REQUESTLINE = 2048;
732774
char buf[BUFSIZ_REQUESTLINE];
733-
if (!fgets(buf, BUFSIZ_REQUESTLINE, fp)) {
775+
if (!detail::socket_gets(sock, buf, BUFSIZ_REQUESTLINE)) {
734776
return false;
735777
}
736778

@@ -803,18 +845,18 @@ inline bool Server::dispatch_request(Request& req, Response& res, Handlers& hand
803845
return false;
804846
}
805847

806-
inline void Server::process_request(FILE* fp_read, FILE* fp_write)
848+
inline void Server::process_request(socket_t sock)
807849
{
808850
Request req;
809851
Response res;
810852

811-
if (!read_request_line(fp_read, req) ||
812-
!detail::read_headers(fp_read, req.headers)) {
853+
if (!read_request_line(sock, req) ||
854+
!detail::read_headers(sock, req.headers)) {
813855
return;
814856
}
815857

816858
if (req.method == "POST") {
817-
if (!detail::read_content(req, fp_read)) {
859+
if (!detail::read_content(sock, req)) {
818860
return;
819861
}
820862
static std::string type = "application/x-www-form-urlencoded";
@@ -836,8 +878,7 @@ inline void Server::process_request(FILE* fp_read, FILE* fp_write)
836878
error_handler_(req, res);
837879
}
838880

839-
detail::write_response(fp_write, req, res);
840-
fflush(fp_write);
881+
detail::write_response(sock, req, res);
841882

842883
if (logger_) {
843884
logger_(req, res);
@@ -851,11 +892,11 @@ inline Client::Client(const char* host, int port)
851892
{
852893
}
853894

854-
inline bool Client::read_response_line(FILE* fp, Response& res)
895+
inline bool Client::read_response_line(socket_t sock, Response& res)
855896
{
856897
const auto BUFSIZ_RESPONSELINE = 2048;
857898
char buf[BUFSIZ_RESPONSELINE];
858-
if (!fgets(buf, BUFSIZ_RESPONSELINE, fp)) {
899+
if (!detail::socket_gets(sock, buf, BUFSIZ_RESPONSELINE)) {
859900
return false;
860901
}
861902

@@ -876,18 +917,17 @@ inline bool Client::send(const Request& req, Response& res)
876917
return false;
877918
}
878919

879-
return detail::read_and_close_socket(sock, [&](FILE* fp_read, FILE* fp_write) {
920+
return detail::read_and_close_socket(sock, [&](socket_t sock) {
880921
// Send request
881-
detail::write_request(fp_write, req);
882-
fflush(fp_write);
922+
detail::write_request(sock, req);
883923

884924
// Receive response
885-
if (!read_response_line(fp_read, res) ||
886-
!detail::read_headers(fp_read, res.headers)) {
925+
if (!read_response_line(sock, res) ||
926+
!detail::read_headers(sock, res.headers)) {
887927
return false;
888928
}
889929
if (req.method != "HEAD") {
890-
if (!detail::read_content(res, fp_read)) {
930+
if (!detail::read_content(sock, res)) {
891931
return false;
892932
}
893933
}

0 commit comments

Comments
 (0)