235 lines
8.6 KiB
C++
235 lines
8.6 KiB
C++
#pragma once
|
|
|
|
#ifdef WITH_NETWORKING
|
|
|
|
#include <v8.h>
|
|
#include <string>
|
|
#include <memory>
|
|
#include <map>
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <queue>
|
|
#include <atomic>
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
#ifdef WITH_SSL
|
|
#ifndef _WIN32
|
|
#include <openssl/ssl.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/crypto.h>
|
|
#endif
|
|
#endif
|
|
|
|
namespace HttpRequestWrapper {
|
|
|
|
enum ReadyState {
|
|
UNSENT = 0,
|
|
OPENED = 1,
|
|
HEADERS_RECEIVED = 2,
|
|
LOADING = 3,
|
|
DONE = 4
|
|
};
|
|
|
|
enum ResponseType {
|
|
DEFAULT = 0,
|
|
ARRAY_BUFFER = 1,
|
|
BLOB = 2,
|
|
DOCUMENT = 3,
|
|
JSON = 4,
|
|
TEXT = 5
|
|
};
|
|
|
|
struct HttpResponse {
|
|
int status;
|
|
std::string statusText;
|
|
std::map<std::string, std::string> headers;
|
|
std::string responseText;
|
|
std::string error;
|
|
|
|
HttpResponse() : status(0), statusText("") {}
|
|
};
|
|
|
|
class HttpRequestClient {
|
|
public:
|
|
HttpRequestClient(v8::Isolate* isolate, v8::Global<v8::Context>* global_context);
|
|
~HttpRequestClient();
|
|
|
|
void open(const std::string& method, const std::string& url, bool async = true);
|
|
void setRequestHeader(const std::string& header, const std::string& value);
|
|
void send(const std::string& data = "");
|
|
void abort();
|
|
std::string getAllResponseHeaders();
|
|
std::string getResponseHeader(const std::string& header);
|
|
|
|
ReadyState getReadyState() const { return ready_state_; }
|
|
int getStatus() const { return response_.status; }
|
|
std::string getStatusText() const { return response_.statusText; }
|
|
std::string getResponseText() const { return response_.responseText; }
|
|
std::string getResponseURL() const { return url_; }
|
|
ResponseType getResponseType() const { return response_type_; }
|
|
int getTimeout() const { return timeout_; }
|
|
bool getWithCredentials() const { return with_credentials_; }
|
|
|
|
void setTimeout(int timeout) { timeout_ = timeout; }
|
|
void setResponseType(ResponseType type) { response_type_ = type; }
|
|
void setWithCredentials(bool withCredentials) { with_credentials_ = withCredentials; }
|
|
|
|
void setOnReadyStateChange(v8::Local<v8::Function> callback);
|
|
void setOnLoad(v8::Local<v8::Function> callback);
|
|
void setOnError(v8::Local<v8::Function> callback);
|
|
void setOnTimeout(v8::Local<v8::Function> callback);
|
|
void setOnAbort(v8::Local<v8::Function> callback);
|
|
void setOnProgress(v8::Local<v8::Function> callback);
|
|
void setOnLoadStart(v8::Local<v8::Function> callback);
|
|
void setOnLoadEnd(v8::Local<v8::Function> callback);
|
|
|
|
// from main thread
|
|
void processEvents();
|
|
|
|
private:
|
|
v8::Isolate* isolate_;
|
|
v8::Global<v8::Context>* global_context_;
|
|
std::string method_;
|
|
std::string url_;
|
|
std::map<std::string, std::string> request_headers_;
|
|
std::string request_data_;
|
|
HttpResponse response_;
|
|
ReadyState ready_state_;
|
|
ResponseType response_type_;
|
|
int timeout_;
|
|
bool with_credentials_;
|
|
bool async_;
|
|
std::thread request_thread_;
|
|
std::atomic<bool> should_abort_;
|
|
|
|
v8::Global<v8::Function> on_ready_state_change_;
|
|
v8::Global<v8::Function> on_load_;
|
|
v8::Global<v8::Function> on_error_;
|
|
v8::Global<v8::Function> on_timeout_;
|
|
v8::Global<v8::Function> on_abort_;
|
|
v8::Global<v8::Function> on_progress_;
|
|
v8::Global<v8::Function> on_load_start_;
|
|
v8::Global<v8::Function> on_load_end_;
|
|
|
|
std::mutex state_mutex_;
|
|
|
|
public:
|
|
std::atomic<bool> active_operation_{false};
|
|
|
|
private:
|
|
// TODO: find real solution for duplicate done
|
|
bool done_event_fired_{false};
|
|
|
|
#ifdef WITH_SSL
|
|
#ifdef _WIN32
|
|
void* ssl_cred_handle_;
|
|
void* ssl_context_handle_;
|
|
bool ssl_context_initialized_;
|
|
int ssl_socket_;
|
|
std::vector<char> ssl_buffer_;
|
|
#else
|
|
SSL_CTX* ssl_ctx_;
|
|
SSL* ssl_;
|
|
bool ssl_initialized_;
|
|
#endif
|
|
bool initSSL();
|
|
void cleanupSSL();
|
|
bool performSSLHandshake(int socket, const std::string& host);
|
|
int sslRead(char* buffer, int length);
|
|
int sslWrite(const char* buffer, int length);
|
|
#endif
|
|
|
|
enum EventType {
|
|
HTTP_READY_STATE_CHANGE = 100,
|
|
HTTP_LOAD = 101,
|
|
HTTP_ERROR = 102,
|
|
HTTP_TIMEOUT = 103,
|
|
HTTP_ABORT = 104,
|
|
HTTP_PROGRESS = 105,
|
|
HTTP_LOAD_START = 106,
|
|
HTTP_LOAD_END = 107
|
|
};
|
|
|
|
struct Event {
|
|
EventType type;
|
|
std::string data;
|
|
int code;
|
|
|
|
Event(EventType t, const std::string& d = "", int c = 0)
|
|
: type(t), data(d), code(c) {}
|
|
};
|
|
|
|
std::queue<Event> event_queue_;
|
|
std::mutex event_queue_mutex_;
|
|
|
|
// handle* called from background thread
|
|
void handleReadyStateChange();
|
|
void handleLoad();
|
|
void handleError(const std::string& error);
|
|
void handleTimeout();
|
|
void handleAbort();
|
|
void handleProgress();
|
|
void handleLoadStart();
|
|
void handleLoadEnd();
|
|
|
|
// process* called from main thread
|
|
void processReadyStateChangeEvent();
|
|
void processLoadEvent();
|
|
void processErrorEvent(const std::string& error);
|
|
void processTimeoutEvent();
|
|
void processAbortEvent();
|
|
void processProgressEvent();
|
|
void processLoadStartEvent();
|
|
void processLoadEndEvent();
|
|
|
|
void performRequest();
|
|
void loadLocalFile(const std::string& path);
|
|
void setReadyState(ReadyState state);
|
|
void callReadyStateChangeCallback();
|
|
void callCallback(v8::Global<v8::Function>& callback, int argc, v8::Local<v8::Value> argv[]);
|
|
|
|
bool parseUrl(const std::string& url, std::string& host, int& port, std::string& path, bool& is_https);
|
|
std::string formatHttpRequest(const std::string& method, const std::string& path, const std::string& host, const std::string& data);
|
|
void parseHttpResponse(const std::string& response);
|
|
};
|
|
|
|
void initialize();
|
|
void cleanup();
|
|
|
|
// process events from main thread
|
|
void processEvents();
|
|
|
|
int createHttpRequest(v8::Isolate* isolate);
|
|
|
|
v8::Global<v8::Context>* getGlobalContext();
|
|
}
|
|
|
|
// V8 binding functions called from main.cpp
|
|
void runt_httprequest_create(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_open(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_send(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_abort(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_request_header(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_get_all_response_headers(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_get_response_header(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_get_ready_state(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_get_status(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_get_status_text(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_get_response_text(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_get_response_url(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_timeout(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_response_type(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_with_credentials(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_onreadystatechange(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_onload(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_onerror(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_ontimeout(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_onabort(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_onprogress(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_onloadstart(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void runt_httprequest_set_onloadend(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
void createXMLHttpRequestClass(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate>& global);
|
|
|
|
#endif |