-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
31 changed files
with
1,175 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"configurations": [ | ||
{ | ||
"name": "Win32", | ||
"includePath": [ | ||
"${workspaceFolder}/**" | ||
], | ||
"defines": [ | ||
"_DEBUG", | ||
"UNICODE", | ||
"_UNICODE" | ||
], | ||
"windowsSdkVersion": "10.0.19041.0", | ||
"compilerPath": "D:/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.31.31103/bin/Hostx64/x64/cl.exe", | ||
"cStandard": "c17", | ||
"cppStandard": "c++17", | ||
"intelliSenseMode": "windows-msvc-x64" | ||
} | ||
], | ||
"version": 4 | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
{ | ||
"files.associations": { | ||
"ostream": "cpp", | ||
"string": "cpp", | ||
"algorithm": "cpp", | ||
"atomic": "cpp", | ||
"bit": "cpp", | ||
"cctype": "cpp", | ||
"charconv": "cpp", | ||
"chrono": "cpp", | ||
"clocale": "cpp", | ||
"cmath": "cpp", | ||
"compare": "cpp", | ||
"concepts": "cpp", | ||
"cstddef": "cpp", | ||
"cstdint": "cpp", | ||
"cstdio": "cpp", | ||
"cstdlib": "cpp", | ||
"cstring": "cpp", | ||
"ctime": "cpp", | ||
"cwchar": "cpp", | ||
"deque": "cpp", | ||
"exception": "cpp", | ||
"format": "cpp", | ||
"forward_list": "cpp", | ||
"initializer_list": "cpp", | ||
"iomanip": "cpp", | ||
"ios": "cpp", | ||
"iosfwd": "cpp", | ||
"iostream": "cpp", | ||
"istream": "cpp", | ||
"iterator": "cpp", | ||
"limits": "cpp", | ||
"locale": "cpp", | ||
"map": "cpp", | ||
"memory": "cpp", | ||
"mutex": "cpp", | ||
"new": "cpp", | ||
"optional": "cpp", | ||
"queue": "cpp", | ||
"ratio": "cpp", | ||
"sstream": "cpp", | ||
"stdexcept": "cpp", | ||
"stop_token": "cpp", | ||
"streambuf": "cpp", | ||
"system_error": "cpp", | ||
"thread": "cpp", | ||
"tuple": "cpp", | ||
"type_traits": "cpp", | ||
"typeinfo": "cpp", | ||
"utility": "cpp", | ||
"vector": "cpp", | ||
"xfacet": "cpp", | ||
"xiosbase": "cpp", | ||
"xlocale": "cpp", | ||
"xlocbuf": "cpp", | ||
"xlocinfo": "cpp", | ||
"xlocmes": "cpp", | ||
"xlocmon": "cpp", | ||
"xlocnum": "cpp", | ||
"xloctime": "cpp", | ||
"xmemory": "cpp", | ||
"xstddef": "cpp", | ||
"xstring": "cpp", | ||
"xtr1common": "cpp", | ||
"xtree": "cpp", | ||
"xutility": "cpp", | ||
"list": "cpp", | ||
"unordered_map": "cpp", | ||
"xhash": "cpp", | ||
"functional": "cpp", | ||
"fstream": "cpp" | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
.PHONY: clean | ||
|
||
CC = g++ | ||
CCFLAGS = -std=c++17 -Wall -lpthread -lm | ||
SOURCE = main.cpp | ||
|
||
all: $(SOURCE) | ||
$(CC) $(SOURCE) -o main $(CCFLAGS) | ||
|
||
run: $(SOURCE) | ||
$(CC) $(SOURCE) -o main $(CCFLAGS) | ||
./main | ||
|
||
debug: $(SOURCE) | ||
$(CC) $(SOURCE) -o main $(CCFLAGS) -DDEBUG | ||
|
||
clean: | ||
rm main |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,9 @@ | ||
# Mini-HTTP-Server | ||
# Mini HTTP Server | ||
|
||
Implementation of a simple HTTP server listening at port 80 on local machine. It supports: | ||
|
||
- multiple TCP connections | ||
- GET and POST methods | ||
- multiple content types such as `text/html`, `image/jpeg`, `text/plain`, `application/octet-stream`, forms, etc. | ||
- easy way to configure more paths because of functional programming | ||
- flexibility since we used a thread pool |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#pragma once | ||
|
||
enum class HTTPMethod { | ||
mUnknown, | ||
mGET, | ||
mPOST, | ||
mPUT, | ||
mDELETE | ||
}; | ||
|
||
enum class HTTPStatusCode { | ||
mOk = 200, | ||
mBadRequest = 400, | ||
mUnauthorized = 401, | ||
mForbidden = 403, | ||
mNotFound = 404, | ||
mInternalServerError = 500, | ||
mBadGateway = 502, | ||
mServiceUnavailable = 503, | ||
mGatewayTimeout = 504 | ||
}; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <iostream> | ||
#include <fstream> | ||
#include "request.hpp" | ||
#include "response.hpp" | ||
#include "enums.h" | ||
|
||
#define BUFFERSIZE 65535 | ||
|
||
void badRequest(HTTPResponse &res) { | ||
res.setStatusCode(HTTPStatusCode::mBadRequest); | ||
res.setHeader("Content-Length", "0"); | ||
} | ||
|
||
void handleGET(const HTTPRequest &req, HTTPResponse &res){ | ||
std::string fileurl = req.getUrl(); | ||
std::ifstream fin(std::string("/mnt/d/courses/network/lab3/test") + fileurl, std::ios::binary); | ||
if (!fin) { | ||
fileurl = req.getUrl() + ".html"; | ||
fin.open(std::string("/mnt/d/courses/network/lab3/test") + fileurl, std::ios::binary); | ||
} | ||
if (!fin) { | ||
fileurl = req.getUrl() + "/index.html"; | ||
fin.open(std::string("/mnt/d/courses/network/lab3/test") + fileurl, std::ios::binary); | ||
} | ||
if (!fin) { | ||
res.setStatusCode(HTTPStatusCode::mNotFound); | ||
res.setHeader("Content-Type", "application/json"); | ||
res.setHeader("Content-Length", "0"); | ||
return; | ||
} | ||
res.setStatusCode(HTTPStatusCode::mOk); | ||
size_t splitpos = fileurl.find_last_of("."); | ||
std::string format = splitpos == std::string::npos ? "no" : fileurl.substr(splitpos + 1); | ||
if (format == "html") res.setHeader("Content-Type", "text/html;charset=utf-8"); | ||
else if (format == "jpg" || format == "jpeg") res.setHeader("Content-Type", "image/jpeg"); | ||
else if (format == "txt") res.setHeader("Content-Type", "text/plain"); | ||
else res.setHeader("Content-Type", "application/octet-stream"); | ||
char *buffer = new char[BUFFERSIZE]; | ||
fin.seekg(0, std::ios::end); | ||
std::streampos endpos = fin.tellg(); | ||
res.setHeader("Content-Length", std::to_string(endpos)); | ||
fin.seekg(0, std::ios::beg); | ||
fin.read(buffer, endpos); | ||
fin.close(); | ||
res.appendContent(std::string(buffer, endpos)); | ||
delete buffer; | ||
} | ||
|
||
void handleDOPOST(const HTTPRequest &req, HTTPResponse &res){ | ||
std::string login = req.getBodyVal("login"); | ||
std::string pass = req.getBodyVal("pass"); | ||
res.setStatusCode(HTTPStatusCode::mOk); | ||
res.setHeader("Content-Type", "text/plain;charset=utf-8"); | ||
if (login.length() == 10 && login.substr(login.length() - 4) == pass) { | ||
res.setHeader("Content-Length", std::to_string(strlen("登录成功"))); | ||
res.appendContent("登录成功"); | ||
} else { | ||
res.setHeader("Content-Length", std::to_string(strlen("登录失败"))); | ||
res.appendContent("登录失败"); | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
#pragma once | ||
|
||
#include <iostream> | ||
#include <sstream> | ||
#include <unordered_map> | ||
#include "enums.h" | ||
|
||
#define BUFFERSIZE 65535 | ||
|
||
class HTTPRequest { | ||
public: | ||
HTTPRequest() {} | ||
HTTPRequest(const char* buf, const size_t &bufsize) { | ||
parseRequest(buf, bufsize); | ||
} | ||
std::string parseRequest(const char* buf, const int64_t &bufsize) { | ||
// 先判断是不是 http | ||
bool ishttp = false; | ||
for (int i = 0; i < bufsize - 3; ++ i) { | ||
if (buf[i] == '\r' && buf[i + 1] == '\n' && | ||
buf[i + 2] == '\r' && buf[i + 3] == '\n') { | ||
ishttp = true; | ||
break; | ||
} | ||
} | ||
if (!ishttp) return std::string("Not HTTP"); | ||
|
||
char linebuf[BUFFERSIZE]; | ||
std::stringstream ss; | ||
ss << std::string(buf, bufsize); | ||
ss.getline(linebuf, BUFFERSIZE); | ||
std::stringstream parserss(linebuf); | ||
std::string method, encodedurl, version; | ||
parserss >> method >> encodedurl >> version; | ||
|
||
if (version != "HTTP/1.1") { | ||
return std::string("Unsupported http version"); | ||
} | ||
|
||
// 方法 | ||
if (method == "GET") { | ||
_method = HTTPMethod::mGET; | ||
} else if (method == "POST") { | ||
_method = HTTPMethod::mPOST; | ||
} else if (method == "PUT") { | ||
_method = HTTPMethod::mPUT; | ||
} else if (method == "DELETE") { | ||
_method = HTTPMethod::mDELETE; | ||
} else { | ||
_method = HTTPMethod::mUnknown; | ||
} | ||
if (_method != HTTPMethod::mGET && _method != HTTPMethod::mPOST) { | ||
return std::string("Unsupported method " + method); | ||
} | ||
|
||
// url 和参数 | ||
size_t splitpos = encodedurl.find_first_of("?#"); | ||
if (splitpos == std::string::npos) _url = encodedurl; | ||
else { | ||
_url = encodedurl.substr(0, splitpos); | ||
std::string paramstr; | ||
if (encodedurl[splitpos] == '?') { | ||
do { | ||
size_t prepos = splitpos; | ||
splitpos = encodedurl.find_first_of("&#", splitpos + 1); | ||
if (splitpos == std::string::npos) splitpos = encodedurl.length(); | ||
paramstr = encodedurl.substr(prepos + 1, (splitpos - prepos - 1)); | ||
size_t spl = paramstr.find_first_of("="); | ||
_params[paramstr.substr(0, spl)] = paramstr.substr(spl + 1); | ||
} while (splitpos != encodedurl.length() && encodedurl[splitpos] != '#'); | ||
} | ||
} | ||
|
||
if (_url[_url.length() - 1] == '/') _url.pop_back(); | ||
|
||
// http headers | ||
for(ss.getline(linebuf, BUFFERSIZE);;ss.getline(linebuf, BUFFERSIZE)) { | ||
if (linebuf[0] == '\r') break; | ||
std::string headerstr(linebuf); | ||
size_t splitpos = headerstr.find_first_of(":"); | ||
_headers[headerstr.substr(0, splitpos)] = headerstr.substr(splitpos + 2); | ||
} | ||
|
||
#ifdef DEBUG | ||
std::cerr << "Method: " << method << "; URL: " << _url << "; Params: " << _params.size() | ||
<< "; Headers: " << _headers.size() << std::endl; | ||
#endif | ||
|
||
// post body | ||
std::string content = ""; | ||
int contentlen = _headers["Content-Length"] == "" ? 0 : std::stoi(_headers["Content-Length"]); | ||
if (contentlen == 0) return "Ok"; | ||
while(ss.getline(linebuf, BUFFERSIZE)) { | ||
content += linebuf; | ||
} | ||
if (_headers["Content-Type"].find("application/x-www-form-urlencoded") != std::string::npos) { | ||
std::string paramstr = ""; | ||
do { | ||
size_t prepos = splitpos; | ||
splitpos = content.find_first_of("&", splitpos + 1); | ||
if (splitpos == std::string::npos) splitpos = content.length(); | ||
paramstr = content.substr(prepos + 1, (splitpos - prepos - 1)); | ||
size_t spl = paramstr.find_first_of("="); | ||
_body[paramstr.substr(0, spl)] = paramstr.substr(spl + 1); | ||
} while (splitpos != content.length() && content[splitpos] != '#'); | ||
} else if (_headers["Content-Type"].find("application/json") != std::string::npos) { | ||
// TO-DO | ||
if (_method != HTTPMethod::mGET) return "Unsupported Content-Type: Neglected"; | ||
else return "Ok"; | ||
} else { | ||
if (_method != HTTPMethod::mGET) return "Unsupported Content-Type: Neglected"; | ||
else return "Ok"; | ||
} | ||
|
||
return "Ok"; | ||
} | ||
|
||
HTTPMethod getMethod() const { | ||
return _method; | ||
} | ||
|
||
std::string getUrl() const { | ||
return _url; | ||
} | ||
|
||
std::string getHeaderVal(const std::string &key) const { | ||
return _headers.find(key)->second; | ||
} | ||
|
||
std::string getParamVal(const std::string &key) const { | ||
return _params.find(key)->second; | ||
} | ||
|
||
std::string getBodyVal(const std::string &key) const { | ||
return _body.find(key)->second; | ||
} | ||
|
||
std::unordered_map<std::string, std::string>* getBodyMapPtr() { | ||
return &_body; | ||
} | ||
|
||
private: | ||
HTTPMethod _method; | ||
std::string _url; | ||
std::unordered_map<std::string, std::string> _headers; | ||
std::unordered_map<std::string, std::string> _params; | ||
std::unordered_map<std::string, std::string> _body; | ||
}; |
Oops, something went wrong.