Last active
April 24, 2018 19:57
-
-
Save curiousleo/efd817d622b1956dfe812d79e164415f to your computer and use it in GitHub Desktop.
Oversimplified HTTP server in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <netdb.h> | |
#include <sys/socket.h> | |
#include <unistd.h> | |
#include <algorithm> | |
#include <cerrno> | |
#include <cstring> | |
#include <iostream> | |
#include <sstream> | |
#include <string> | |
#include <string_view> | |
#include <unordered_map> | |
#include <vector> | |
using addrinfo_t = struct addrinfo; | |
class Connection { | |
int sock; | |
std::vector<unsigned char> buf; | |
std::string read_until(std::string_view delim); | |
public: | |
explicit Connection(int sock) | |
: sock(sock), buf(std::vector<unsigned char>()) {} | |
std::string read_line(); | |
}; | |
int bind_socket(std::string_view port); | |
int set_reusable(int sock); | |
static const int RECV_SIZE = 3; | |
int main() { | |
const int s = bind_socket("9322"); | |
if (listen(s, 0) == -1) { | |
std::cerr << "listen: " << strerror(errno) << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
const int in = accept(s, nullptr, nullptr); | |
if (in == -1) { | |
std::cerr << "accept: " << strerror(errno) << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
Connection c(in); | |
std::string method, path, version; | |
std::istringstream(c.read_line()) >> method >> path >> version; | |
std::unordered_map<std::string, std::string> hdrs{}; | |
for (std::string l = c.read_line(); !l.empty(); l = c.read_line()) { | |
const size_t nsep = l.find(':'); | |
std::string k(l.cbegin(), l.cbegin() + nsep); | |
std::string v(l.cbegin() + nsep + 2, l.cend()); | |
std::transform(k.begin(), k.end(), k.begin(), ::tolower); | |
hdrs[k] = v; | |
} | |
return 0; | |
} | |
std::string Connection::read_line() { return read_until("\r\n"); } | |
std::string Connection::read_until(std::string_view delim) { | |
auto it = search(buf.begin(), buf.end(), delim.begin(), delim.end()); | |
for (; it == buf.end(); | |
it = search(buf.begin(), buf.end(), delim.begin(), delim.end())) { | |
buf.resize(buf.size() + RECV_SIZE); | |
const int r = recvfrom(sock, &*(buf.end() - RECV_SIZE), RECV_SIZE, 0, | |
nullptr, nullptr); | |
if (r == -1) { | |
std::cerr << "recvfrom: " << strerror(errno) << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
if (r == 0) { | |
std::string s(std::make_move_iterator(buf.begin()), | |
std::make_move_iterator(buf.end())); | |
buf.clear(); | |
return s; | |
} | |
} | |
std::string s(std::make_move_iterator(buf.begin()), | |
std::make_move_iterator(it)); | |
buf.erase(buf.begin(), it + delim.size()); | |
return s; | |
} | |
int bind_socket(std::string_view port) { | |
addrinfo_t hints = {}; | |
hints.ai_family = AF_INET; | |
hints.ai_socktype = SOCK_STREAM; | |
addrinfo_t* ai_head; | |
{ | |
int err = getaddrinfo(nullptr, port.data(), &hints, &ai_head); | |
if (err != 0) { | |
std::cerr << "getaddrinfo: " << strerror(errno) << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
} | |
for (addrinfo_t* ai = ai_head; ai != nullptr; ai = ai->ai_next) { | |
const int s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | |
if (s == -1) { | |
continue; | |
} | |
if (set_reusable(s) == -1) { | |
std::cerr << "setsockopt: " << strerror(errno) << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
if (bind(s, ai->ai_addr, ai->ai_addrlen) == 0) { | |
freeaddrinfo(ai_head); | |
return s; | |
} | |
close(s); | |
} | |
std::cerr << "could not bind" << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
int set_reusable(const int sock) { | |
const int yes = 1; | |
return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, | |
static_cast<const void*>(&yes), sizeof(int)); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/bash | |
clang-tidy -checks=*,-llvm-include-order -extra-arg=-std=c++17 -header-filter="^include" -p . -fix muhttp.cpp | |
clang-format -style=google -i muhttp.cpp | |
clang++ -std=c++17 -Wall -Wextra -Wpedantic -g -o muhttp muhttp.cpp | |
./muhttp |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment