emsApplication/3rdPartner/libhv/http/server/HttpHandler.h

187 lines
4.8 KiB
C
Raw Permalink Normal View History

2024-05-24 12:19:45 +08:00
#ifndef HV_HTTP_HANDLER_H_
#define HV_HTTP_HANDLER_H_
#include "HttpService.h"
#include "HttpParser.h"
#include "FileCache.h"
#include "WebSocketServer.h"
#include "WebSocketParser.h"
class HttpHandler {
public:
enum ProtocolType {
UNKNOWN,
HTTP_V1,
HTTP_V2,
WEBSOCKET,
} protocol;
enum State {
WANT_RECV,
HANDLE_BEGIN,
HANDLE_CONTINUE,
HANDLE_END,
WANT_SEND,
SEND_HEADER,
SEND_BODY,
SEND_DONE,
WANT_CLOSE,
} state;
// errno
int error;
// flags
unsigned ssl :1;
unsigned keepalive :1;
unsigned upgrade :1;
unsigned proxy :1;
unsigned proxy_connected :1;
unsigned forward_proxy :1;
unsigned reverse_proxy :1;
// peeraddr
char ip[64];
int port;
// for log
long pid;
long tid;
// for http
hio_t *io;
HttpService *service;
HttpRequestPtr req;
HttpResponsePtr resp;
HttpResponseWriterPtr writer;
HttpParserPtr parser;
HttpContextPtr ctx;
http_handler* api_handler;
// for GetSendData
std::string header;
// std::string body;
// for websocket
WebSocketService* ws_service;
WebSocketChannelPtr ws_channel;
WebSocketParserPtr ws_parser;
uint64_t last_send_ping_time;
uint64_t last_recv_pong_time;
// for sendfile
FileCache *files;
file_cache_ptr fc; // cache small file
struct LargeFile : public HFile {
HBuf buf;
uint64_t timer;
} *file; // for large file
// for proxy
std::string proxy_host;
int proxy_port;
HttpHandler(hio_t* io = NULL);
~HttpHandler();
bool Init(int http_version = 1);
void Reset();
void Close();
/* @workflow:
* HttpServer::on_recv -> HttpHandler::FeedRecvData -> Init -> HttpParser::InitRequest -> HttpRequest::http_cb ->
* onHeadersComplete -> proxy ? handleProxy -> connectProxy :
* onMessageComplete -> upgrade ? handleUpgrade : HandleHttpRequest -> HttpParser::SubmitResponse ->
* SendHttpResponse -> while(GetSendData) hio_write ->
* keepalive ? Reset : Close -> hio_close
*
* @return
* == len: ok
* == 0: WANT_CLOSE
* < 0: error
*/
int FeedRecvData(const char* data, size_t len);
/* @workflow:
* preprocessor -> middleware -> processor -> postprocessor
*
* @return status_code
* == 0: HANDLE_CONTINUE
* != 0: HANDLE_END
*/
int HandleHttpRequest();
int GetSendData(char** data, size_t* len);
int SendHttpResponse(bool submit = true);
int SendHttpStatusResponse(http_status status_code);
// HTTP2
bool SwitchHTTP2();
// websocket
bool SwitchWebSocket();
void WebSocketOnOpen() {
ws_channel->status = hv::SocketChannel::CONNECTED;
if (ws_service && ws_service->onopen) {
ws_service->onopen(ws_channel, req);
}
}
void WebSocketOnClose() {
ws_channel->status = hv::SocketChannel::DISCONNECTED;
if (ws_service && ws_service->onclose) {
ws_service->onclose(ws_channel);
}
}
int SetError(int error_code, http_status status_code = HTTP_STATUS_BAD_REQUEST) {
error = error_code;
if (resp) resp->status_code = status_code;
return error;
}
private:
const HttpContextPtr& context();
int handleRequestHeaders();
// Expect: 100-continue
void handleExpect100();
void addResponseHeaders();
// http_cb
void onHeadersComplete();
void onBody(const char* data, size_t size);
void onMessageComplete();
// default handlers
int defaultRequestHandler();
int defaultStaticHandler();
int defaultLargeFileHandler();
int defaultErrorHandler();
int customHttpHandler(const http_handler& handler);
int invokeHttpHandler(const http_handler* handler);
// sendfile
int openFile(const char* filepath);
int sendFile();
void closeFile();
bool isFileOpened();
// upgrade
int handleUpgrade(const char* upgrade_protocol);
int upgradeWebSocket();
int upgradeHTTP2();
// proxy
int handleProxy();
int handleForwardProxy();
int handleReverseProxy();
int connectProxy(const std::string& url);
int closeProxy();
int sendProxyRequest();
static void onProxyConnect(hio_t* upstream_io);
static void onProxyClose(hio_t* upstream_io);
};
#endif // HV_HTTP_HANDLER_H_