Files
integration/luprex/core/cpp/http.hpp

232 lines
7.6 KiB
C++
Raw Normal View History

2022-03-29 16:50:26 -04:00
/////////////////////////////////////////////////////////
//
// HTTP Implementation.
//
// This is a fairly limited implementation of HTTP.
//
// It only supports HTTP 1.1
//
// It only supports GET, POST, and HEAD.
//
/////////////////////////////////////////////////////////
#ifndef HTTP_HPP
#define HTTP_HPP
#include "eng-malloc.hpp"
#include "wrap-string.hpp"
#include "wrap-vector.hpp"
#include "wrap-map.hpp"
2022-03-29 16:50:26 -04:00
#include "luastack.hpp"
#include "streambuffer.hpp"
2022-03-29 16:50:26 -04:00
2022-04-25 13:43:11 -04:00
using UrlParameters = eng::map<eng::string, eng::string>;
class HttpOutRequest : public eng::nevernew {
private:
// Request IDs.
int64_t request_id_;
int64_t place_id_;
int64_t thread_id_;
// If the request contains an error, the error
// message is stored here.
eng::string error_;
2022-03-29 16:50:26 -04:00
// If true, verify the server's certificate.
// True is the default.
bool verify_certificate_;
// Method: GET, HEAD, POST, etc. Must be all-caps.
eng::string method_;
// The hostname. Not yet url-encoded.
2022-03-29 16:50:26 -04:00
eng::string host_;
// Port number.
2022-03-29 16:50:26 -04:00
int port_;
// The path. Not yet url-encoded. Can not include URL parameters.
eng::string path_;
// URL parameters to append to the path. Not yet url-encoded.
2022-04-25 13:43:11 -04:00
UrlParameters params_;
private:
2022-04-25 13:43:11 -04:00
void fail(std::string_view error);
void send_internal(StreamBuffer *target, bool debug_string) const;
2022-03-29 16:50:26 -04:00
public:
// Construct an empty HTTP request.
// All of the fields have empty values.
2022-04-25 13:43:11 -04:00
HttpOutRequest();
// Get the request IDs.
int64_t request_id() const { return request_id_; }
int64_t place_id() const { return place_id_; }
int64_t thread_id() const { return thread_id_; }
// Get request-related fields.
const eng::string &error() const { return error_; }
bool verify_certificate() const { return verify_certificate_; }
const eng::string &method() const { return method_; }
const eng::string &host() const { return host_; }
int port() const { return port_; }
const eng::string &path() const { return path_; }
// Get the network target, eg, "cert:host:port"
eng::string target() const;
// Set the request IDs.
void set_request_id(int64_t request_id) { request_id_ = request_id; }
void set_place_id(int64_t place_id) { place_id_ = place_id; }
void set_thread_id(int64_t thread_id) { thread_id_ = thread_id; }
// Populate an HTTP request a piece at a time.
// If you pass an invalid value, or if the field is
// already set, the routine will generate an error message
// and store it in the error field. In that case, the set
// will not happen. If there's already an error in the error
// field, it will not be overwritten.
void set_verify_certificate(bool flag);
void set_method(const eng::string &method);
void set_host(const eng::string &host);
void set_port(int port);
2022-04-25 13:43:11 -04:00
void set_path(std::string_view path);
void set_param(const eng::string &key, const eng::string &value);
2022-04-25 13:43:11 -04:00
void set_url(std::string_view url);
// Same as above, but using Lua values.
void set_verify_certificate(LuaStack &LS, LuaSlot val);
void set_method(LuaStack &LS, LuaSlot val);
void set_host(LuaStack &LS, LuaSlot val);
void set_port(LuaStack &LS, LuaSlot val);
2022-04-25 13:43:11 -04:00
void set_path(LuaStack &LS, LuaSlot path);
void set_param(LuaStack &LS, LuaSlot key, LuaSlot val);
void set_params(LuaStack &LS, LuaSlot tab);
2022-04-25 13:43:11 -04:00
void set_url(LuaStack &LS, LuaSlot val);
// Set default values for any fields that should have
// defaults. This must be done after setting regular
// values.
void set_defaults();
// Verify that the request is error free and that
// defaults have been set.
eng::string check() const;
// Populate an HTTP request from a Lua table.
void set_config(LuaStack &LS0, LuaSlot tab);
// Put the request into the stream, assuming HTTP/1.1
void send(StreamBuffer *target) const { send_internal(target, false); }
// Serialize and deserialize.
void serialize(StreamBuffer *sb) const;
void deserialize(StreamBuffer *sb);
// Get the request as a debug string.
eng::string DebugString();
};
class HttpOutRequestMap : public eng::map<int64_t, HttpOutRequest> {
public:
void serialize(StreamBuffer *sb) const;
void deserialize(StreamBuffer *sb);
};
2022-04-25 13:43:11 -04:00
class HttpInResponse {
private:
2022-04-25 13:43:11 -04:00
// The HTTP response status code.
int status_code_;
// If the HTTP response contains an error, the
// error message is stored here. If the HTTP response
// is a success such as "200 OK" or "201 Created", this
// is the empty string, not "OK" or "Created".
eng::string error_;
2022-04-25 13:43:11 -04:00
// Only if content-length header present, otherwise, -1.
int64_t content_length_;
// If empty, it means there was no transfer-encoding header.
eng::string transfer_encoding_;
// If empty, it means there was no content-encoding header.
eng::string content_encoding_;
// Only if location header present.
eng::string location_;
// MIME type of the content.
2022-03-29 16:50:26 -04:00
eng::string mime_type_;
2022-04-25 13:43:11 -04:00
// Charset of the content. Hopefully utf-8.
eng::string charset_;
// The content as string.
2022-03-29 16:50:26 -04:00
eng::string content_;
2022-04-25 13:43:11 -04:00
// The length in bytes of the entire response.
// May be zero, which means that the response
// was so garbled that we couldn't determine the length.
int response_length_;
private:
2022-04-25 13:43:11 -04:00
// Store a message indicating that we haven't received enough
// bytes yet. If the connection is closed and we still haven't
// received enough bytes, that's a fatal error.
void incomplete(bool closed);
// Parse a response header. Most headers are ignored.
// If the header contains an error, the error is stored.
void parse_header(std::string_view header, std::string_view value);
// Parse specific headers.
// For several headers, all we do is verify that they aren't
// invoking unsupported features.
void parse_content_encoding(std::string_view value);
void parse_content_length(std::string_view value);
void parse_content_type(std::string_view value);
void parse_location(std::string_view value);
void parse_transfer_encoding(std::string_view value);
// parse the body
bool parse_content_basic(std::string_view &view, bool closed);
bool parse_content_chunked(std::string_view &view, bool closed);
public:
2022-04-25 13:43:11 -04:00
const int64_t MAX_CONTENT_LENGTH = 1000000;
// Construct a blank response.
2022-04-25 13:43:11 -04:00
HttpInResponse();
2022-04-25 13:43:11 -04:00
// Store a result code and an error message, and clear the content.
// This is generally used when the client detects an error,
// such as a DNS lookup fail, a connection failed, an SSL negotiation
2022-04-25 13:43:11 -04:00
// failed, or the like.
void fail(int status_code, std::string_view error);
// Parse the HTTP response. The closed flag is to be set to true if the
// remote has closed the connection.
//
// If the request is incomplete, generates a 600 incomplete error. In that
// case, loading more data from the server might improve the situation.
//
// Note that the response is not ever removed from the StreamBuffer, which
// is always unmodified. If you want to remove the response from the
// StreamBuffer, see response_length.
//
void parse(const StreamBuffer *sb, bool closed);
// Convert the HTTP response to a lua table.
void store(LuaStack &LS, LuaSlot tab) const;
2022-04-25 13:43:11 -04:00
// Convert to a debug string.
eng::string DebugString() const;
// Synthesize an error response and store it in lua.
static void store_fail(LuaStack &LS, LuaSlot tab, int status_code, std::string_view error);
2022-03-29 16:50:26 -04:00
};
#endif // HTTP_HPP