mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-12 06:27:12 +03:00
move to new cspot
This commit is contained in:
787
components/spotify/cspot/bell/external/civetweb/CivetServer.cpp
vendored
Normal file
787
components/spotify/cspot/bell/external/civetweb/CivetServer.cpp
vendored
Normal file
@@ -0,0 +1,787 @@
|
||||
/* Copyright (c) 2013-2020 the Civetweb developers
|
||||
* Copyright (c) 2013 No Face Press, LLC
|
||||
*
|
||||
* License http://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
#include "CivetServer.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdexcept>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef UNUSED_PARAMETER
|
||||
#define UNUSED_PARAMETER(x) (void)(x)
|
||||
#endif
|
||||
|
||||
#ifndef MAX_PARAM_BODY_LENGTH
|
||||
// Set a default limit for parameters in a form body: 2 MB
|
||||
#define MAX_PARAM_BODY_LENGTH (1024 * 1024 * 2)
|
||||
#endif
|
||||
|
||||
bool
|
||||
CivetHandler::handleGet(CivetServer *server, struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handleGet(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
if (status_code) {
|
||||
*status_code = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handlePost(CivetServer *server, struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handlePost(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
if (status_code) {
|
||||
*status_code = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handleHead(CivetServer *server, struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handleHead(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
if (status_code) {
|
||||
*status_code = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handlePut(CivetServer *server, struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handlePut(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
if (status_code) {
|
||||
*status_code = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handlePatch(CivetServer *server, struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handlePatch(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
if (status_code) {
|
||||
*status_code = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handleDelete(CivetServer *server, struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handleDelete(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
if (status_code) {
|
||||
*status_code = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handleOptions(CivetServer *server, struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetHandler::handleOptions(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
if (status_code) {
|
||||
*status_code = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetWebSocketHandler::handleConnection(CivetServer *server,
|
||||
const struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CivetWebSocketHandler::handleReadyState(CivetServer *server,
|
||||
struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetWebSocketHandler::handleData(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int bits,
|
||||
char *data,
|
||||
size_t data_len)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
UNUSED_PARAMETER(bits);
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(data_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CivetWebSocketHandler::handleClose(CivetServer *server,
|
||||
const struct mg_connection *conn)
|
||||
{
|
||||
UNUSED_PARAMETER(server);
|
||||
UNUSED_PARAMETER(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
CivetServer::requestHandler(struct mg_connection *conn, void *cbdata)
|
||||
{
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
assert(request_info != NULL);
|
||||
CivetServer *me = (CivetServer *)(request_info->user_data);
|
||||
assert(me != NULL);
|
||||
int http_status_code = -1;
|
||||
bool status_ok = false;
|
||||
|
||||
// Happens when a request hits the server before the context is saved
|
||||
if (me->context == NULL)
|
||||
return 0;
|
||||
|
||||
mg_lock_context(me->context);
|
||||
me->connections[conn] = CivetConnection();
|
||||
mg_unlock_context(me->context);
|
||||
|
||||
CivetHandler *handler = (CivetHandler *)cbdata;
|
||||
|
||||
if (handler) {
|
||||
if (strcmp(request_info->request_method, "GET") == 0) {
|
||||
status_ok = handler->handleGet(me, conn, &http_status_code);
|
||||
if (http_status_code < 0) {
|
||||
status_ok = handler->handleGet(me, conn);
|
||||
}
|
||||
} else if (strcmp(request_info->request_method, "POST") == 0) {
|
||||
status_ok = handler->handlePost(me, conn, &http_status_code);
|
||||
if (http_status_code < 0) {
|
||||
status_ok = handler->handlePost(me, conn);
|
||||
}
|
||||
} else if (strcmp(request_info->request_method, "HEAD") == 0) {
|
||||
status_ok = handler->handleHead(me, conn, &http_status_code);
|
||||
if (http_status_code < 0) {
|
||||
status_ok = handler->handleHead(me, conn);
|
||||
}
|
||||
} else if (strcmp(request_info->request_method, "PUT") == 0) {
|
||||
status_ok = handler->handlePut(me, conn, &http_status_code);
|
||||
if (http_status_code < 0) {
|
||||
status_ok = handler->handlePut(me, conn);
|
||||
}
|
||||
} else if (strcmp(request_info->request_method, "DELETE") == 0) {
|
||||
status_ok = handler->handleDelete(me, conn, &http_status_code);
|
||||
if (http_status_code < 0) {
|
||||
status_ok = handler->handleDelete(me, conn);
|
||||
}
|
||||
} else if (strcmp(request_info->request_method, "OPTIONS") == 0) {
|
||||
status_ok = handler->handleOptions(me, conn, &http_status_code);
|
||||
if (http_status_code < 0) {
|
||||
status_ok = handler->handleOptions(me, conn);
|
||||
}
|
||||
} else if (strcmp(request_info->request_method, "PATCH") == 0) {
|
||||
status_ok = handler->handlePatch(me, conn, &http_status_code);
|
||||
if (http_status_code < 0) {
|
||||
status_ok = handler->handlePatch(me, conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (http_status_code < 0) {
|
||||
http_status_code = status_ok ? 1 : 0;
|
||||
}
|
||||
|
||||
return http_status_code;
|
||||
}
|
||||
|
||||
int
|
||||
CivetServer::authHandler(struct mg_connection *conn, void *cbdata)
|
||||
{
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
assert(request_info != NULL);
|
||||
CivetServer *me = (CivetServer *)(request_info->user_data);
|
||||
assert(me != NULL);
|
||||
|
||||
// Happens when a request hits the server before the context is saved
|
||||
if (me->context == NULL)
|
||||
return 0;
|
||||
|
||||
mg_lock_context(me->context);
|
||||
me->connections[conn] = CivetConnection();
|
||||
mg_unlock_context(me->context);
|
||||
|
||||
CivetAuthHandler *handler = (CivetAuthHandler *)cbdata;
|
||||
|
||||
if (handler) {
|
||||
return handler->authorize(me, conn) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0; // No handler found
|
||||
}
|
||||
|
||||
int
|
||||
CivetServer::webSocketConnectionHandler(const struct mg_connection *conn,
|
||||
void *cbdata)
|
||||
{
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
assert(request_info != NULL);
|
||||
CivetServer *me = (CivetServer *)(request_info->user_data);
|
||||
assert(me != NULL);
|
||||
|
||||
// Happens when a request hits the server before the context is saved
|
||||
if (me->context == NULL)
|
||||
return 0;
|
||||
|
||||
CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
|
||||
|
||||
if (handler) {
|
||||
return handler->handleConnection(me, conn) ? 0 : 1;
|
||||
}
|
||||
|
||||
return 1; // No handler found, close connection
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::webSocketReadyHandler(struct mg_connection *conn, void *cbdata)
|
||||
{
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
assert(request_info != NULL);
|
||||
CivetServer *me = (CivetServer *)(request_info->user_data);
|
||||
assert(me != NULL);
|
||||
|
||||
// Happens when a request hits the server before the context is saved
|
||||
if (me->context == NULL)
|
||||
return;
|
||||
|
||||
CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
|
||||
|
||||
if (handler) {
|
||||
handler->handleReadyState(me, conn);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CivetServer::webSocketDataHandler(struct mg_connection *conn,
|
||||
int bits,
|
||||
char *data,
|
||||
size_t data_len,
|
||||
void *cbdata)
|
||||
{
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
assert(request_info != NULL);
|
||||
CivetServer *me = (CivetServer *)(request_info->user_data);
|
||||
assert(me != NULL);
|
||||
|
||||
// Happens when a request hits the server before the context is saved
|
||||
if (me->context == NULL)
|
||||
return 0;
|
||||
|
||||
CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
|
||||
|
||||
if (handler) {
|
||||
return handler->handleData(me, conn, bits, data, data_len) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 1; // No handler found
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::webSocketCloseHandler(const struct mg_connection *conn,
|
||||
void *cbdata)
|
||||
{
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
assert(request_info != NULL);
|
||||
CivetServer *me = (CivetServer *)(request_info->user_data);
|
||||
assert(me != NULL);
|
||||
|
||||
// Happens when a request hits the server before the context is saved
|
||||
if (me->context == NULL)
|
||||
return;
|
||||
|
||||
CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
|
||||
|
||||
if (handler) {
|
||||
handler->handleClose(me, conn);
|
||||
}
|
||||
}
|
||||
|
||||
CivetCallbacks::CivetCallbacks()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
CivetServer::CivetServer(const char **options,
|
||||
const struct CivetCallbacks *_callbacks,
|
||||
const void *UserContextIn)
|
||||
: context(0)
|
||||
{
|
||||
struct CivetCallbacks callbacks;
|
||||
|
||||
UserContext = UserContextIn;
|
||||
|
||||
if (_callbacks) {
|
||||
callbacks = *_callbacks;
|
||||
userCloseHandler = _callbacks->connection_close;
|
||||
} else {
|
||||
userCloseHandler = NULL;
|
||||
}
|
||||
callbacks.connection_close = closeHandler;
|
||||
struct mg_init_data mg_start_init_data = {0};
|
||||
mg_start_init_data.callbacks = &callbacks;
|
||||
mg_start_init_data.user_data = this;
|
||||
mg_start_init_data.configuration_options = options;
|
||||
|
||||
struct mg_error_data mg_start_error_data = {0};
|
||||
char errtxtbuf[256] = {0};
|
||||
mg_start_error_data.text = errtxtbuf;
|
||||
mg_start_error_data.text_buffer_size = sizeof(errtxtbuf);
|
||||
|
||||
context = mg_start2(&mg_start_init_data, &mg_start_error_data);
|
||||
|
||||
if (context == NULL) {
|
||||
|
||||
std::string exceptionMsg =
|
||||
"null context when constructing CivetServer. "
|
||||
"Possible problem binding to port. Error: ";
|
||||
exceptionMsg += errtxtbuf;
|
||||
|
||||
printf("CivetServer: %s\n", exceptionMsg.c_str());
|
||||
throw CivetException(exceptionMsg);
|
||||
}
|
||||
}
|
||||
|
||||
CivetServer::CivetServer(const std::vector<std::string> &options,
|
||||
const struct CivetCallbacks *_callbacks,
|
||||
const void *UserContextIn)
|
||||
: context(0)
|
||||
{
|
||||
struct CivetCallbacks callbacks;
|
||||
|
||||
UserContext = UserContextIn;
|
||||
|
||||
if (_callbacks) {
|
||||
callbacks = *_callbacks;
|
||||
userCloseHandler = _callbacks->connection_close;
|
||||
} else {
|
||||
userCloseHandler = NULL;
|
||||
}
|
||||
callbacks.connection_close = closeHandler;
|
||||
|
||||
std::vector<const char *> pointers(options.size() + 1);
|
||||
for (size_t i = 0; i < options.size(); i++) {
|
||||
pointers[i] = (options[i].c_str());
|
||||
}
|
||||
pointers.back() = NULL;
|
||||
|
||||
struct mg_init_data mg_start_init_data = {0};
|
||||
mg_start_init_data.callbacks = &callbacks;
|
||||
mg_start_init_data.user_data = this;
|
||||
mg_start_init_data.configuration_options = &pointers[0];
|
||||
|
||||
struct mg_error_data mg_start_error_data = {0};
|
||||
char errtxtbuf[256] = {0};
|
||||
mg_start_error_data.text = errtxtbuf;
|
||||
mg_start_error_data.text_buffer_size = sizeof(errtxtbuf);
|
||||
|
||||
context = mg_start2(&mg_start_init_data, &mg_start_error_data);
|
||||
|
||||
if (context == NULL) {
|
||||
std::string exceptionMsg =
|
||||
"null context when constructing CivetServer. "
|
||||
"Possible problem binding to port. Error: ";
|
||||
exceptionMsg += errtxtbuf;
|
||||
throw CivetException(exceptionMsg);
|
||||
}
|
||||
}
|
||||
|
||||
CivetServer::~CivetServer()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::closeHandler(const struct mg_connection *conn)
|
||||
{
|
||||
CivetServer *me = (CivetServer *)mg_get_user_data(mg_get_context(conn));
|
||||
assert(me != NULL);
|
||||
|
||||
// Happens when a request hits the server before the context is saved
|
||||
if (me->context == NULL)
|
||||
return;
|
||||
|
||||
if (me->userCloseHandler) {
|
||||
me->userCloseHandler(conn);
|
||||
}
|
||||
mg_lock_context(me->context);
|
||||
me->connections.erase(conn);
|
||||
mg_unlock_context(me->context);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::addHandler(const std::string &uri, CivetHandler *handler)
|
||||
{
|
||||
mg_set_request_handler(context, uri.c_str(), requestHandler, handler);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::addWebSocketHandler(const std::string &uri,
|
||||
CivetWebSocketHandler *handler)
|
||||
{
|
||||
mg_set_websocket_handler(context,
|
||||
uri.c_str(),
|
||||
webSocketConnectionHandler,
|
||||
webSocketReadyHandler,
|
||||
webSocketDataHandler,
|
||||
webSocketCloseHandler,
|
||||
handler);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::addAuthHandler(const std::string &uri, CivetAuthHandler *handler)
|
||||
{
|
||||
mg_set_auth_handler(context, uri.c_str(), authHandler, handler);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::removeHandler(const std::string &uri)
|
||||
{
|
||||
mg_set_request_handler(context, uri.c_str(), NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::removeWebSocketHandler(const std::string &uri)
|
||||
{
|
||||
mg_set_websocket_handler(
|
||||
context, uri.c_str(), NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::removeAuthHandler(const std::string &uri)
|
||||
{
|
||||
mg_set_auth_handler(context, uri.c_str(), NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::close()
|
||||
{
|
||||
if (context) {
|
||||
mg_stop(context);
|
||||
context = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CivetServer::getCookie(struct mg_connection *conn,
|
||||
const std::string &cookieName,
|
||||
std::string &cookieValue)
|
||||
{
|
||||
// Maximum cookie length as per microsoft is 4096.
|
||||
// http://msdn.microsoft.com/en-us/library/ms178194.aspx
|
||||
char _cookieValue[4096];
|
||||
const char *cookie = mg_get_header(conn, "Cookie");
|
||||
int lRead = mg_get_cookie(cookie,
|
||||
cookieName.c_str(),
|
||||
_cookieValue,
|
||||
sizeof(_cookieValue));
|
||||
cookieValue.clear();
|
||||
cookieValue.append(_cookieValue);
|
||||
return lRead;
|
||||
}
|
||||
|
||||
const char *
|
||||
CivetServer::getHeader(struct mg_connection *conn,
|
||||
const std::string &headerName)
|
||||
{
|
||||
return mg_get_header(conn, headerName.c_str());
|
||||
}
|
||||
|
||||
const char *
|
||||
CivetServer::getMethod(struct mg_connection *conn)
|
||||
{
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
assert(request_info != NULL);
|
||||
return request_info->request_method;
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::urlDecode(const char *src,
|
||||
std::string &dst,
|
||||
bool is_form_url_encoded)
|
||||
{
|
||||
urlDecode(src, strlen(src), dst, is_form_url_encoded);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::urlDecode(const char *src,
|
||||
size_t src_len,
|
||||
std::string &dst,
|
||||
bool is_form_url_encoded)
|
||||
{
|
||||
// assign enough buffer
|
||||
std::vector<char> buf(src_len + 1);
|
||||
int r = mg_url_decode(src,
|
||||
static_cast<int>(src_len),
|
||||
&buf[0],
|
||||
static_cast<int>(buf.size()),
|
||||
is_form_url_encoded);
|
||||
if (r < 0) {
|
||||
// never reach here
|
||||
throw std::out_of_range("");
|
||||
}
|
||||
// dst can contain NUL characters
|
||||
dst.assign(buf.begin(), buf.begin() + r);
|
||||
}
|
||||
|
||||
bool
|
||||
CivetServer::getParam(struct mg_connection *conn,
|
||||
const char *name,
|
||||
std::string &dst,
|
||||
size_t occurrence)
|
||||
{
|
||||
const char *formParams = NULL;
|
||||
const char *queryString = NULL;
|
||||
const struct mg_request_info *ri = mg_get_request_info(conn);
|
||||
assert(ri != NULL);
|
||||
CivetServer *me = (CivetServer *)(ri->user_data);
|
||||
assert(me != NULL);
|
||||
mg_lock_context(me->context);
|
||||
CivetConnection &conobj = me->connections[conn];
|
||||
mg_unlock_context(me->context);
|
||||
|
||||
mg_lock_connection(conn);
|
||||
if (conobj.postData.empty()) {
|
||||
// check if there is a request body
|
||||
for (;;) {
|
||||
char buf[2048];
|
||||
int r = mg_read(conn, buf, sizeof(buf));
|
||||
try {
|
||||
if (r == 0) {
|
||||
conobj.postData.push_back('\0');
|
||||
break;
|
||||
} else if ((r < 0)
|
||||
|| ((conobj.postData.size() + r)
|
||||
> MAX_PARAM_BODY_LENGTH)) {
|
||||
conobj.postData.assign(1, '\0');
|
||||
break;
|
||||
}
|
||||
conobj.postData.insert(conobj.postData.end(), buf, buf + r);
|
||||
} catch (...) {
|
||||
conobj.postData.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!conobj.postData.empty()) {
|
||||
// check if form parameter are already stored
|
||||
formParams = &conobj.postData[0];
|
||||
}
|
||||
|
||||
if (ri->query_string != NULL) {
|
||||
// get requests do store html <form> field values in the http
|
||||
// query_string
|
||||
queryString = ri->query_string;
|
||||
}
|
||||
|
||||
mg_unlock_connection(conn);
|
||||
|
||||
bool get_param_success = false;
|
||||
if (formParams != NULL) {
|
||||
get_param_success =
|
||||
getParam(formParams, strlen(formParams), name, dst, occurrence);
|
||||
}
|
||||
if (!get_param_success && queryString != NULL) {
|
||||
get_param_success =
|
||||
getParam(queryString, strlen(queryString), name, dst, occurrence);
|
||||
}
|
||||
|
||||
return get_param_success;
|
||||
}
|
||||
|
||||
bool
|
||||
CivetServer::getParam(const char *data,
|
||||
size_t data_len,
|
||||
const char *name,
|
||||
std::string &dst,
|
||||
size_t occurrence)
|
||||
{
|
||||
char buf[256];
|
||||
int r = mg_get_var2(data, data_len, name, buf, sizeof(buf), occurrence);
|
||||
if (r >= 0) {
|
||||
// dst can contain NUL characters
|
||||
dst.assign(buf, r);
|
||||
return true;
|
||||
} else if (r == -2) {
|
||||
// more buffer
|
||||
std::vector<char> vbuf(sizeof(buf) * 2);
|
||||
for (;;) {
|
||||
r = mg_get_var2(
|
||||
data, data_len, name, &vbuf[0], vbuf.size(), occurrence);
|
||||
if (r >= 0) {
|
||||
dst.assign(vbuf.begin(), vbuf.begin() + r);
|
||||
return true;
|
||||
} else if (r != -2) {
|
||||
break;
|
||||
}
|
||||
// more buffer
|
||||
vbuf.resize(vbuf.size() * 2);
|
||||
}
|
||||
}
|
||||
dst.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string
|
||||
CivetServer::getPostData(struct mg_connection *conn)
|
||||
{
|
||||
mg_lock_connection(conn);
|
||||
std::string postdata;
|
||||
char buf[2048];
|
||||
int r = mg_read(conn, buf, sizeof(buf));
|
||||
while (r > 0) {
|
||||
postdata.append(buf, r);
|
||||
r = mg_read(conn, buf, sizeof(buf));
|
||||
}
|
||||
mg_unlock_connection(conn);
|
||||
return postdata;
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::urlEncode(const char *src, std::string &dst, bool append)
|
||||
{
|
||||
urlEncode(src, strlen(src), dst, append);
|
||||
}
|
||||
|
||||
void
|
||||
CivetServer::urlEncode(const char *src,
|
||||
size_t src_len,
|
||||
std::string &dst,
|
||||
bool append)
|
||||
{
|
||||
if (!append)
|
||||
dst.clear();
|
||||
|
||||
for (; src_len > 0; src++, src_len--) {
|
||||
if (*src == '\0') {
|
||||
// src and dst can contain NUL characters without encoding
|
||||
dst.push_back(*src);
|
||||
} else {
|
||||
char buf[2] = {*src, '\0'};
|
||||
char dst_buf[4];
|
||||
if (mg_url_encode(buf, dst_buf, sizeof(dst_buf)) < 0) {
|
||||
// never reach here
|
||||
throw std::out_of_range("");
|
||||
}
|
||||
dst.append(dst_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int>
|
||||
CivetServer::getListeningPorts()
|
||||
{
|
||||
std::vector<struct mg_server_port> server_ports = getListeningPortsFull();
|
||||
|
||||
std::vector<int> ports(server_ports.size());
|
||||
for (size_t i = 0; i < server_ports.size(); i++) {
|
||||
ports[i] = server_ports[i].port;
|
||||
}
|
||||
|
||||
return ports;
|
||||
}
|
||||
|
||||
std::vector<struct mg_server_port>
|
||||
CivetServer::getListeningPortsFull()
|
||||
{
|
||||
std::vector<struct mg_server_port> server_ports(8);
|
||||
for (;;) {
|
||||
int size = mg_get_server_ports(context,
|
||||
static_cast<int>(server_ports.size()),
|
||||
&server_ports[0]);
|
||||
if (size < static_cast<int>(server_ports.size())) {
|
||||
server_ports.resize(size < 0 ? 0 : size);
|
||||
break;
|
||||
}
|
||||
server_ports.resize(server_ports.size() * 2);
|
||||
}
|
||||
return server_ports;
|
||||
}
|
||||
22625
components/spotify/cspot/bell/external/civetweb/civetweb.c
vendored
Normal file
22625
components/spotify/cspot/bell/external/civetweb/civetweb.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
components/spotify/cspot/bell/external/civetweb/external_log_access.inl
vendored
Normal file
5
components/spotify/cspot/bell/external/civetweb/external_log_access.inl
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "civetweb.h"
|
||||
|
||||
static void log_access(const struct mg_connection *conn) {
|
||||
|
||||
}
|
||||
4
components/spotify/cspot/bell/external/civetweb/external_mg_cry_internal_impl.inl
vendored
Normal file
4
components/spotify/cspot/bell/external/civetweb/external_mg_cry_internal_impl.inl
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "civetweb.h"
|
||||
|
||||
static void
|
||||
mg_cry_internal_impl(const struct mg_connection *conn, const char *func, unsigned line, const char *fmt, va_list ap) {}
|
||||
1082
components/spotify/cspot/bell/external/civetweb/handle_form.inl
vendored
Normal file
1082
components/spotify/cspot/bell/external/civetweb/handle_form.inl
vendored
Normal file
File diff suppressed because it is too large
Load Diff
736
components/spotify/cspot/bell/external/civetweb/include/CivetServer.h
vendored
Normal file
736
components/spotify/cspot/bell/external/civetweb/include/CivetServer.h
vendored
Normal file
@@ -0,0 +1,736 @@
|
||||
/* Copyright (c) 2013-2017 the Civetweb developers
|
||||
* Copyright (c) 2013 No Face Press, LLC
|
||||
*
|
||||
* License http://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
#ifndef CIVETSERVER_HEADER_INCLUDED
|
||||
#define CIVETSERVER_HEADER_INCLUDED
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "civetweb.h"
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifndef CIVETWEB_CXX_API
|
||||
#if defined(_WIN32)
|
||||
#if defined(CIVETWEB_CXX_DLL_EXPORTS)
|
||||
#define CIVETWEB_CXX_API __declspec(dllexport)
|
||||
#elif defined(CIVETWEB_CXX_DLL_IMPORTS)
|
||||
#define CIVETWEB_CXX_API __declspec(dllimport)
|
||||
#else
|
||||
#define CIVETWEB_CXX_API
|
||||
#endif
|
||||
#elif __GNUC__ >= 4
|
||||
#define CIVETWEB_CXX_API __attribute__((visibility("default")))
|
||||
#else
|
||||
#define CIVETWEB_CXX_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// forward declaration
|
||||
class CivetServer;
|
||||
|
||||
/**
|
||||
* Exception class for thrown exceptions within the CivetHandler object.
|
||||
*/
|
||||
class CIVETWEB_CXX_API CivetException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
CivetException(const std::string &msg) : std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic interface for a URI request handler. Handlers implementations
|
||||
* must be reentrant.
|
||||
*/
|
||||
class CIVETWEB_CXX_API CivetHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CivetHandler()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for GET request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handleGet(CivetServer *server, struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for GET request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @param status_code - pointer to return status code
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handleGet(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code);
|
||||
|
||||
/**
|
||||
* Callback method for POST request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handlePost(CivetServer *server, struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for POST request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @param status_code - pointer to return status code
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handlePost(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code);
|
||||
|
||||
/**
|
||||
* Callback method for HEAD request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handleHead(CivetServer *server, struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for HEAD request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @param status_code - pointer to return status code
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handleHead(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code);
|
||||
|
||||
/**
|
||||
* Callback method for PUT request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handlePut(CivetServer *server, struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for PUT request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @param status_code - pointer to return status code
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handlePut(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code);
|
||||
|
||||
/**
|
||||
* Callback method for DELETE request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handleDelete(CivetServer *server, struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for DELETE request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @param status_code - pointer to return status code
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handleDelete(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code);
|
||||
|
||||
/**
|
||||
* Callback method for OPTIONS request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handleOptions(CivetServer *server, struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for OPTIONS request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @param status_code - pointer to return status code
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handleOptions(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code);
|
||||
|
||||
/**
|
||||
* Callback method for PATCH request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handlePatch(CivetServer *server, struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for PATCH request.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @param status_code - pointer to return status code
|
||||
* @returns true if implemented, false otherwise
|
||||
*/
|
||||
virtual bool handlePatch(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int *status_code);
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic interface for a URI authorization handler. Handler implementations
|
||||
* must be reentrant.
|
||||
*/
|
||||
class CIVETWEB_CXX_API CivetAuthHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CivetAuthHandler()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for authorization requests. It is up the this handler
|
||||
* to generate 401 responses if authorization fails.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true if authorization succeeded, false otherwise
|
||||
*/
|
||||
virtual bool authorize(CivetServer *server, struct mg_connection *conn) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic interface for a websocket handler. Handlers implementations
|
||||
* must be reentrant.
|
||||
*/
|
||||
class CIVETWEB_CXX_API CivetWebSocketHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CivetWebSocketHandler()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for when the client intends to establish a websocket
|
||||
*connection, before websocket handshake.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @returns true to keep socket open, false to close it
|
||||
*/
|
||||
virtual bool handleConnection(CivetServer *server,
|
||||
const struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for when websocket handshake is successfully completed,
|
||||
*and connection is ready for data exchange.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
*/
|
||||
virtual void handleReadyState(CivetServer *server,
|
||||
struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Callback method for when a data frame has been received from the client.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
* @bits: first byte of the websocket frame, see websocket RFC at
|
||||
*http://tools.ietf.org/html/rfc6455, section 5.2
|
||||
* @data, data_len: payload, with mask (if any) already applied.
|
||||
* @returns true to keep socket open, false to close it
|
||||
*/
|
||||
virtual bool handleData(CivetServer *server,
|
||||
struct mg_connection *conn,
|
||||
int bits,
|
||||
char *data,
|
||||
size_t data_len);
|
||||
|
||||
/**
|
||||
* Callback method for when the connection is closed.
|
||||
*
|
||||
* @param server - the calling server
|
||||
* @param conn - the connection information
|
||||
*/
|
||||
virtual void handleClose(CivetServer *server,
|
||||
const struct mg_connection *conn);
|
||||
};
|
||||
|
||||
/**
|
||||
* CivetCallbacks
|
||||
*
|
||||
* wrapper for mg_callbacks
|
||||
*/
|
||||
struct CIVETWEB_CXX_API CivetCallbacks : public mg_callbacks {
|
||||
CivetCallbacks();
|
||||
};
|
||||
|
||||
/**
|
||||
* CivetServer
|
||||
*
|
||||
* Basic class for embedded web server. This has an URL mapping built-in.
|
||||
*/
|
||||
class CIVETWEB_CXX_API CivetServer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* This automatically starts the sever.
|
||||
* It is good practice to call getContext() after this in case there
|
||||
* were errors starting the server.
|
||||
*
|
||||
* Note: CivetServer should not be used as a static instance in a Windows
|
||||
* DLL, since the constructor creates threads and the destructor joins
|
||||
* them again (creating/joining threads should not be done in static
|
||||
* constructors).
|
||||
*
|
||||
* @param options - the web server options.
|
||||
* @param callbacks - optional web server callback methods.
|
||||
*
|
||||
* @throws CivetException
|
||||
*/
|
||||
CivetServer(const char **options,
|
||||
const struct CivetCallbacks *callbacks = 0,
|
||||
const void *UserContext = 0);
|
||||
CivetServer(const std::vector<std::string> &options,
|
||||
const struct CivetCallbacks *callbacks = 0,
|
||||
const void *UserContext = 0);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CivetServer();
|
||||
|
||||
/**
|
||||
* close()
|
||||
*
|
||||
* Stops server and frees resources.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* getContext()
|
||||
*
|
||||
* @return the context or 0 if not running.
|
||||
*/
|
||||
const struct mg_context *
|
||||
getContext() const
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* addHandler(const std::string &, CivetHandler *)
|
||||
*
|
||||
* Adds a URI handler. If there is existing URI handler, it will
|
||||
* be replaced with this one.
|
||||
*
|
||||
* URI's are ordered and prefix (REST) URI's are supported.
|
||||
*
|
||||
* @param uri - URI to match.
|
||||
* @param handler - handler instance to use.
|
||||
*/
|
||||
void addHandler(const std::string &uri, CivetHandler *handler);
|
||||
|
||||
void
|
||||
addHandler(const std::string &uri, CivetHandler &handler)
|
||||
{
|
||||
addHandler(uri, &handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* addWebSocketHandler
|
||||
*
|
||||
* Adds a WebSocket handler for a specific URI. If there is existing URI
|
||||
*handler, it will
|
||||
* be replaced with this one.
|
||||
*
|
||||
* URI's are ordered and prefix (REST) URI's are supported.
|
||||
*
|
||||
* @param uri - URI to match.
|
||||
* @param handler - handler instance to use.
|
||||
*/
|
||||
void addWebSocketHandler(const std::string &uri,
|
||||
CivetWebSocketHandler *handler);
|
||||
|
||||
void
|
||||
addWebSocketHandler(const std::string &uri, CivetWebSocketHandler &handler)
|
||||
{
|
||||
addWebSocketHandler(uri, &handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* removeHandler(const std::string &)
|
||||
*
|
||||
* Removes a handler.
|
||||
*
|
||||
* @param uri - the exact URL used in addHandler().
|
||||
*/
|
||||
void removeHandler(const std::string &uri);
|
||||
|
||||
/**
|
||||
* removeWebSocketHandler(const std::string &)
|
||||
*
|
||||
* Removes a web socket handler.
|
||||
*
|
||||
* @param uri - the exact URL used in addWebSocketHandler().
|
||||
*/
|
||||
void removeWebSocketHandler(const std::string &uri);
|
||||
|
||||
/**
|
||||
* addAuthHandler(const std::string &, CivetAuthHandler *)
|
||||
*
|
||||
* Adds a URI authorization handler. If there is existing URI authorization
|
||||
* handler, it will be replaced with this one.
|
||||
*
|
||||
* URI's are ordered and prefix (REST) URI's are supported.
|
||||
*
|
||||
* @param uri - URI to match.
|
||||
* @param handler - authorization handler instance to use.
|
||||
*/
|
||||
void addAuthHandler(const std::string &uri, CivetAuthHandler *handler);
|
||||
|
||||
void
|
||||
addAuthHandler(const std::string &uri, CivetAuthHandler &handler)
|
||||
{
|
||||
addAuthHandler(uri, &handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* removeAuthHandler(const std::string &)
|
||||
*
|
||||
* Removes an authorization handler.
|
||||
*
|
||||
* @param uri - the exact URL used in addAuthHandler().
|
||||
*/
|
||||
void removeAuthHandler(const std::string &uri);
|
||||
|
||||
/**
|
||||
* getListeningPorts()
|
||||
*
|
||||
* Returns a list of ports that are listening
|
||||
*
|
||||
* @return A vector of ports
|
||||
*/
|
||||
|
||||
std::vector<int> getListeningPorts();
|
||||
|
||||
/**
|
||||
* getListeningPorts()
|
||||
*
|
||||
* Variant of getListeningPorts() returning the full port information
|
||||
* (protocol, SSL, ...)
|
||||
*
|
||||
* @return A vector of ports
|
||||
*/
|
||||
std::vector<struct mg_server_port> getListeningPortsFull();
|
||||
|
||||
/**
|
||||
* getCookie(struct mg_connection *conn, const std::string &cookieName,
|
||||
* std::string &cookieValue)
|
||||
*
|
||||
* Puts the cookie value string that matches the cookie name in the
|
||||
* cookieValue destination string.
|
||||
*
|
||||
* @param conn - the connection information
|
||||
* @param cookieName - cookie name to get the value from
|
||||
* @param cookieValue - cookie value is returned using this reference
|
||||
* @returns the size of the cookie value string read.
|
||||
*/
|
||||
static int getCookie(struct mg_connection *conn,
|
||||
const std::string &cookieName,
|
||||
std::string &cookieValue);
|
||||
|
||||
/**
|
||||
* getHeader(struct mg_connection *conn, const std::string &headerName)
|
||||
* @param conn - the connection information
|
||||
* @param headerName - header name to get the value from
|
||||
* @returns a char array which contains the header value as string
|
||||
*/
|
||||
static const char *getHeader(struct mg_connection *conn,
|
||||
const std::string &headerName);
|
||||
|
||||
/**
|
||||
* getMethod(struct mg_connection *conn)
|
||||
* @param conn - the connection information
|
||||
* @returns method of HTTP request
|
||||
*/
|
||||
static const char *getMethod(struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* getParam(struct mg_connection *conn, const char *, std::string &, size_t)
|
||||
*
|
||||
* Returns a query which contained in the supplied buffer. The
|
||||
* occurrence value is a zero-based index of a particular key name. This
|
||||
* should not be confused with the index over all of the keys. Note that
|
||||
*this
|
||||
* function assumes that parameters are sent as text in http query string
|
||||
* format, which is the default for web forms. This function will work for
|
||||
* html forms with method="GET" and method="POST" attributes. In other
|
||||
*cases,
|
||||
* you may use a getParam version that directly takes the data instead of
|
||||
*the
|
||||
* connection as a first argument.
|
||||
*
|
||||
* @param conn - parameters are read from the data sent through this
|
||||
*connection
|
||||
* @param name - the key to search for
|
||||
* @param dst - the destination string
|
||||
* @param occurrence - the occurrence of the selected name in the query (0
|
||||
*based).
|
||||
* @return true if key was found
|
||||
*/
|
||||
static bool getParam(struct mg_connection *conn,
|
||||
const char *name,
|
||||
std::string &dst,
|
||||
size_t occurrence = 0);
|
||||
|
||||
/**
|
||||
* getParam(const std::string &, const char *, std::string &, size_t)
|
||||
*
|
||||
* Returns a query parameter contained in the supplied buffer. The
|
||||
* occurrence value is a zero-based index of a particular key name. This
|
||||
* should not be confused with the index over all of the keys.
|
||||
*
|
||||
* @param data - the query string (text)
|
||||
* @param name - the key to search for
|
||||
* @param dst - the destination string
|
||||
* @param occurrence - the occurrence of the selected name in the query (0
|
||||
*based).
|
||||
* @return true if key was found
|
||||
*/
|
||||
static bool
|
||||
getParam(const std::string &data,
|
||||
const char *name,
|
||||
std::string &dst,
|
||||
size_t occurrence = 0)
|
||||
{
|
||||
return getParam(data.c_str(), data.length(), name, dst, occurrence);
|
||||
}
|
||||
|
||||
/**
|
||||
* getParam(const char *, size_t, const char *, std::string &, size_t)
|
||||
*
|
||||
* Returns a query parameter contained in the supplied buffer. The
|
||||
* occurrence value is a zero-based index of a particular key name. This
|
||||
* should not be confused with the index over all of the keys.
|
||||
*
|
||||
* @param data the - query string (text)
|
||||
* @param data_len - length of the query string
|
||||
* @param name - the key to search for
|
||||
* @param dst - the destination string
|
||||
* @param occurrence - the occurrence of the selected name in the query (0
|
||||
*based).
|
||||
* @return true if key was found
|
||||
*/
|
||||
static bool getParam(const char *data,
|
||||
size_t data_len,
|
||||
const char *name,
|
||||
std::string &dst,
|
||||
size_t occurrence = 0);
|
||||
|
||||
/**
|
||||
* getPostData(struct mg_connection *)
|
||||
*
|
||||
* Returns response body from a request made as POST. Since the
|
||||
* connections map is protected, it can't be directly accessed.
|
||||
* This uses string to store post data to handle big posts.
|
||||
*
|
||||
* @param conn - connection from which post data will be read
|
||||
* @return Post data (empty if not available).
|
||||
*/
|
||||
static std::string getPostData(struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* urlDecode(const std::string &, std::string &, bool)
|
||||
*
|
||||
* @param src - string to be decoded
|
||||
* @param dst - destination string
|
||||
* @param is_form_url_encoded - true if form url encoded
|
||||
* form-url-encoded data differs from URI encoding in a way that it
|
||||
* uses '+' as character for space, see RFC 1866 section 8.2.1
|
||||
* http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
|
||||
*/
|
||||
static void
|
||||
urlDecode(const std::string &src,
|
||||
std::string &dst,
|
||||
bool is_form_url_encoded = true)
|
||||
{
|
||||
urlDecode(src.c_str(), src.length(), dst, is_form_url_encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* urlDecode(const char *, size_t, std::string &, bool)
|
||||
*
|
||||
* @param src - buffer to be decoded
|
||||
* @param src_len - length of buffer to be decoded
|
||||
* @param dst - destination string
|
||||
* @param is_form_url_encoded - true if form url encoded
|
||||
* form-url-encoded data differs from URI encoding in a way that it
|
||||
* uses '+' as character for space, see RFC 1866 section 8.2.1
|
||||
* http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
|
||||
*/
|
||||
static void urlDecode(const char *src,
|
||||
size_t src_len,
|
||||
std::string &dst,
|
||||
bool is_form_url_encoded = true);
|
||||
|
||||
/**
|
||||
* urlDecode(const char *, std::string &, bool)
|
||||
*
|
||||
* @param src - buffer to be decoded (0 terminated)
|
||||
* @param dst - destination string
|
||||
* @param is_form_url_encoded true - if form url encoded
|
||||
* form-url-encoded data differs from URI encoding in a way that it
|
||||
* uses '+' as character for space, see RFC 1866 section 8.2.1
|
||||
* http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
|
||||
*/
|
||||
static void urlDecode(const char *src,
|
||||
std::string &dst,
|
||||
bool is_form_url_encoded = true);
|
||||
|
||||
/**
|
||||
* urlEncode(const std::string &, std::string &, bool)
|
||||
*
|
||||
* @param src - buffer to be encoded
|
||||
* @param dst - destination string
|
||||
* @param append - true if string should not be cleared before encoding.
|
||||
*/
|
||||
static void
|
||||
urlEncode(const std::string &src, std::string &dst, bool append = false)
|
||||
{
|
||||
urlEncode(src.c_str(), src.length(), dst, append);
|
||||
}
|
||||
|
||||
/**
|
||||
* urlEncode(const char *, size_t, std::string &, bool)
|
||||
*
|
||||
* @param src - buffer to be encoded (0 terminated)
|
||||
* @param dst - destination string
|
||||
* @param append - true if string should not be cleared before encoding.
|
||||
*/
|
||||
static void
|
||||
urlEncode(const char *src, std::string &dst, bool append = false);
|
||||
|
||||
/**
|
||||
* urlEncode(const char *, size_t, std::string &, bool)
|
||||
*
|
||||
* @param src - buffer to be encoded
|
||||
* @param src_len - length of buffer to be decoded
|
||||
* @param dst - destination string
|
||||
* @param append - true if string should not be cleared before encoding.
|
||||
*/
|
||||
static void urlEncode(const char *src,
|
||||
size_t src_len,
|
||||
std::string &dst,
|
||||
bool append = false);
|
||||
|
||||
// generic user context which can be set/read,
|
||||
// the server does nothing with this apart from keep it.
|
||||
const void *
|
||||
getUserContext() const
|
||||
{
|
||||
return UserContext;
|
||||
}
|
||||
|
||||
protected:
|
||||
class CivetConnection
|
||||
{
|
||||
public:
|
||||
std::vector<char> postData;
|
||||
};
|
||||
|
||||
struct mg_context *context;
|
||||
std::map<const struct mg_connection *, CivetConnection> connections;
|
||||
|
||||
// generic user context which can be set/read,
|
||||
// the server does nothing with this apart from keep it.
|
||||
const void *UserContext;
|
||||
|
||||
private:
|
||||
/**
|
||||
* requestHandler(struct mg_connection *, void *cbdata)
|
||||
*
|
||||
* Handles the incoming request.
|
||||
*
|
||||
* @param conn - the connection information
|
||||
* @param cbdata - pointer to the CivetHandler instance.
|
||||
* @returns 0 if implemented, false otherwise
|
||||
*/
|
||||
static int requestHandler(struct mg_connection *conn, void *cbdata);
|
||||
|
||||
static int webSocketConnectionHandler(const struct mg_connection *conn,
|
||||
void *cbdata);
|
||||
static void webSocketReadyHandler(struct mg_connection *conn, void *cbdata);
|
||||
static int webSocketDataHandler(struct mg_connection *conn,
|
||||
int bits,
|
||||
char *data,
|
||||
size_t data_len,
|
||||
void *cbdata);
|
||||
static void webSocketCloseHandler(const struct mg_connection *conn,
|
||||
void *cbdata);
|
||||
/**
|
||||
* authHandler(struct mg_connection *, void *cbdata)
|
||||
*
|
||||
* Handles the authorization requests.
|
||||
*
|
||||
* @param conn - the connection information
|
||||
* @param cbdata - pointer to the CivetAuthHandler instance.
|
||||
* @returns 1 if authorized, 0 otherwise
|
||||
*/
|
||||
static int authHandler(struct mg_connection *conn, void *cbdata);
|
||||
|
||||
/**
|
||||
* closeHandler(struct mg_connection *)
|
||||
*
|
||||
* Handles closing a request (internal handler)
|
||||
*
|
||||
* @param conn - the connection information
|
||||
*/
|
||||
static void closeHandler(const struct mg_connection *conn);
|
||||
|
||||
/**
|
||||
* Stores the user provided close handler
|
||||
*/
|
||||
void (*userCloseHandler)(const struct mg_connection *conn);
|
||||
};
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif /* CIVETSERVER_HEADER_INCLUDED */
|
||||
12
components/spotify/cspot/bell/external/civetweb/include/civetdefines.h
vendored
Normal file
12
components/spotify/cspot/bell/external/civetweb/include/civetdefines.h
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#define NO_SSL
|
||||
#define USE_WEBSOCKET
|
||||
#define NO_FILESYSTEMS
|
||||
#define NO_FILES
|
||||
#define NO_CGI
|
||||
#define NO_CACHING
|
||||
#define NO_ATOMICS
|
||||
|
||||
#define MG_EXTERNAL_FUNCTION_mg_cry_internal_impl
|
||||
#define MG_EXTERNAL_FUNCTION_log_access
|
||||
1833
components/spotify/cspot/bell/external/civetweb/include/civetweb.h
vendored
Normal file
1833
components/spotify/cspot/bell/external/civetweb/include/civetweb.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
262
components/spotify/cspot/bell/external/civetweb/match.inl
vendored
Normal file
262
components/spotify/cspot/bell/external/civetweb/match.inl
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
/* Reimplementation of pattern matching */
|
||||
/* This file is part of the CivetWeb web server.
|
||||
* See https://github.com/civetweb/civetweb/
|
||||
*/
|
||||
|
||||
|
||||
/* Initialize structure with 0 matches */
|
||||
static void
|
||||
match_context_reset(struct mg_match_context *mcx)
|
||||
{
|
||||
mcx->num_matches = 0;
|
||||
memset(mcx->match, 0, sizeof(mcx->match));
|
||||
}
|
||||
|
||||
|
||||
/* Add a new match to the list of matches */
|
||||
static void
|
||||
match_context_push(const char *str, size_t len, struct mg_match_context *mcx)
|
||||
{
|
||||
if (mcx->num_matches < MG_MATCH_CONTEXT_MAX_MATCHES) {
|
||||
mcx->match[mcx->num_matches].str = str;
|
||||
mcx->match[mcx->num_matches].len = len;
|
||||
mcx->num_matches++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ptrdiff_t
|
||||
mg_match_impl(const char *pat,
|
||||
size_t pat_len,
|
||||
const char *str,
|
||||
struct mg_match_context *mcx)
|
||||
{
|
||||
/* Parse string */
|
||||
size_t i_pat = 0; /* Pattern index */
|
||||
size_t i_str = 0; /* Pattern index */
|
||||
|
||||
uint8_t case_sensitive = ((mcx != NULL) ? mcx->case_sensitive : 0);
|
||||
|
||||
while (i_pat < pat_len) {
|
||||
|
||||
/* Pattern ? matches one character, except / and NULL character */
|
||||
if ((pat[i_pat] == '?') && (str[i_str] != '\0')
|
||||
&& (str[i_str] != '/')) {
|
||||
size_t i_str_start = i_str;
|
||||
do {
|
||||
/* Advance as long as there are ? */
|
||||
i_pat++;
|
||||
i_str++;
|
||||
} while ((pat[i_pat] == '?') && (str[i_str] != '\0')
|
||||
&& (str[i_str] != '/') && (i_pat < pat_len));
|
||||
|
||||
/* If we have a match context, add the substring we just found */
|
||||
if (mcx) {
|
||||
match_context_push(str + i_str_start, i_str - i_str_start, mcx);
|
||||
}
|
||||
|
||||
/* Reached end of pattern ? */
|
||||
if (i_pat == pat_len) {
|
||||
return (ptrdiff_t)i_str;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pattern $ matches end of string */
|
||||
if (pat[i_pat] == '$') {
|
||||
return (str[i_str] == '\0') ? (ptrdiff_t)i_str : -1;
|
||||
}
|
||||
|
||||
/* Pattern * or ** matches multiple characters */
|
||||
if (pat[i_pat] == '*') {
|
||||
size_t len; /* lenght matched by "*" or "**" */
|
||||
ptrdiff_t ret;
|
||||
|
||||
i_pat++;
|
||||
if ((pat[i_pat] == '*') && (i_pat < pat_len)) {
|
||||
/* Pattern ** matches all */
|
||||
i_pat++;
|
||||
len = strlen(str + i_str);
|
||||
} else {
|
||||
/* Pattern * matches all except / character */
|
||||
len = strcspn(str + i_str, "/");
|
||||
}
|
||||
|
||||
if (i_pat == pat_len) {
|
||||
/* End of pattern reached. Add all to match context. */
|
||||
if (mcx) {
|
||||
match_context_push(str + i_str, len, mcx);
|
||||
}
|
||||
return (i_str + len);
|
||||
}
|
||||
|
||||
/* This loop searches for the longest possible match */
|
||||
do {
|
||||
ret = mg_match_impl(pat + i_pat,
|
||||
(pat_len - (size_t)i_pat),
|
||||
str + i_str + len,
|
||||
mcx);
|
||||
} while ((ret == -1) && (len-- > 0));
|
||||
|
||||
/* If we have a match context, add the substring we just found */
|
||||
if (ret >= 0) {
|
||||
if (mcx) {
|
||||
match_context_push(str + i_str, len, mcx);
|
||||
}
|
||||
return (i_str + ret + len);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Single character compare */
|
||||
if (case_sensitive) {
|
||||
if (pat[i_pat] != str[i_str]) {
|
||||
/* case sensitive compare: mismatch */
|
||||
return -1;
|
||||
}
|
||||
} else if (lowercase(&pat[i_pat]) != lowercase(&str[i_str])) {
|
||||
/* case insensitive compare: mismatch */
|
||||
return -1;
|
||||
}
|
||||
|
||||
i_pat++;
|
||||
i_str++;
|
||||
}
|
||||
return (ptrdiff_t)i_str;
|
||||
}
|
||||
|
||||
|
||||
static ptrdiff_t
|
||||
mg_match_alternatives(const char *pat,
|
||||
size_t pat_len,
|
||||
const char *str,
|
||||
struct mg_match_context *mcx)
|
||||
{
|
||||
const char *match_alternative = (const char *)memchr(pat, '|', pat_len);
|
||||
|
||||
if (mcx != NULL) {
|
||||
match_context_reset(mcx);
|
||||
}
|
||||
|
||||
while (match_alternative != NULL) {
|
||||
/* Split at | for alternative match */
|
||||
size_t left_size = (size_t)(match_alternative - pat);
|
||||
|
||||
/* Try left string first */
|
||||
ptrdiff_t ret = mg_match_impl(pat, left_size, str, mcx);
|
||||
if (ret >= 0) {
|
||||
/* A 0-byte match is also valid */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset possible incomplete match data */
|
||||
if (mcx != NULL) {
|
||||
match_context_reset(mcx);
|
||||
}
|
||||
|
||||
/* If no match: try right side */
|
||||
pat += left_size + 1;
|
||||
pat_len -= left_size + 1;
|
||||
match_alternative = (const char *)memchr(pat, '|', pat_len);
|
||||
}
|
||||
|
||||
/* Handled all | operators. This is the final string. */
|
||||
return mg_match_impl(pat, pat_len, str, mcx);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
match_compare(const void *p1, const void *p2, void *user)
|
||||
{
|
||||
const struct mg_match_element *e1 = (const struct mg_match_element *)p1;
|
||||
const struct mg_match_element *e2 = (const struct mg_match_element *)p2;
|
||||
|
||||
/* unused */
|
||||
(void)user;
|
||||
|
||||
if (e1->str > e2->str) {
|
||||
return +1;
|
||||
}
|
||||
if (e1->str < e2->str) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(MG_EXPERIMENTAL_INTERFACES)
|
||||
CIVETWEB_API
|
||||
#else
|
||||
static
|
||||
#endif
|
||||
ptrdiff_t
|
||||
mg_match(const char *pat, const char *str, struct mg_match_context *mcx)
|
||||
{
|
||||
size_t pat_len = strlen(pat);
|
||||
ptrdiff_t ret = mg_match_alternatives(pat, pat_len, str, mcx);
|
||||
if (mcx != NULL) {
|
||||
if (ret < 0) {
|
||||
/* Remove possible incomplete data */
|
||||
match_context_reset(mcx);
|
||||
} else {
|
||||
/* Join "?*" to one pattern. */
|
||||
size_t i, j;
|
||||
|
||||
/* Use difference of two array elements instead of sizeof, since
|
||||
* there may be some additional padding bytes. */
|
||||
size_t elmsize =
|
||||
(size_t)(&mcx->match[1]) - (size_t)(&mcx->match[0]);
|
||||
|
||||
/* First sort the matches by address ("str" begin to end) */
|
||||
mg_sort(mcx->match, mcx->num_matches, elmsize, match_compare, NULL);
|
||||
|
||||
/* Join consecutive matches */
|
||||
i = 1;
|
||||
while (i < mcx->num_matches) {
|
||||
if ((mcx->match[i - 1].str + mcx->match[i - 1].len)
|
||||
== mcx->match[i].str) {
|
||||
/* Two matches are consecutive. Join length. */
|
||||
mcx->match[i - 1].len += mcx->match[i].len;
|
||||
|
||||
/* Shift all list elements. */
|
||||
for (j = i + 1; j < mcx->num_matches; j++) {
|
||||
mcx->match[j - 1].len = mcx->match[j].len;
|
||||
mcx->match[j - 1].str = mcx->match[j].str;
|
||||
}
|
||||
|
||||
/* Remove/blank last list element. */
|
||||
mcx->num_matches--;
|
||||
mcx->match[mcx->num_matches].str = NULL;
|
||||
mcx->match[mcx->num_matches].len = 0;
|
||||
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static ptrdiff_t
|
||||
match_prefix(const char *pattern, size_t pattern_len, const char *str)
|
||||
{
|
||||
if (pattern == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return mg_match_alternatives(pattern, pattern_len, str, NULL);
|
||||
}
|
||||
|
||||
|
||||
static ptrdiff_t
|
||||
match_prefix_strlen(const char *pattern, const char *str)
|
||||
{
|
||||
if (pattern == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return mg_match_alternatives(pattern, strlen(pattern), str, NULL);
|
||||
}
|
||||
|
||||
/* End of match.inl */
|
||||
472
components/spotify/cspot/bell/external/civetweb/md5.inl
vendored
Normal file
472
components/spotify/cspot/bell/external/civetweb/md5.inl
vendored
Normal file
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* This an amalgamation of md5.c and md5.h into a single file
|
||||
* with all static declaration to reduce linker conflicts
|
||||
* in Civetweb.
|
||||
*
|
||||
* The MD5_STATIC declaration was added to facilitate static
|
||||
* inclusion.
|
||||
* No Face Press, LLC
|
||||
*/
|
||||
|
||||
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.h is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#if !defined(md5_INCLUDED)
|
||||
#define md5_INCLUDED
|
||||
|
||||
/*
|
||||
* This package supports both compile-time and run-time determination of CPU
|
||||
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
||||
* defined as non-zero, the code will be compiled to run only on big-endian
|
||||
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
||||
* run on either big- or little-endian CPUs, but will run slightly less
|
||||
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
||||
*/
|
||||
|
||||
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||
|
||||
/* Define the state of the MD5 Algorithm. */
|
||||
typedef struct md5_state_s {
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
} md5_state_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
MD5_STATIC void md5_init(md5_state_t *pms);
|
||||
|
||||
/* Append a string to the message. */
|
||||
MD5_STATIC void
|
||||
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes);
|
||||
|
||||
/* Finish the message and return the digest. */
|
||||
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* md5_INCLUDED */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.c is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||
either statically or dynamically; added missing #include <string.h>
|
||||
in library.
|
||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||
type, in test program and T value program.
|
||||
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||
unsigned in ANSI C, signed in traditional"; made test program
|
||||
self-checking.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#if !defined(MD5_STATIC)
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#if defined(ARCH_IS_BIG_ENDIAN)
|
||||
#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||
#else
|
||||
#define BYTE_ORDER (0)
|
||||
#endif
|
||||
|
||||
#define T_MASK ((md5_word_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 (0x242070db)
|
||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 (0x4787c62a)
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#define T9 (0x698098d8)
|
||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||
#define T13 (0x6b901122)
|
||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 (0x49b40821)
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 (0x265e5a51)
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 (0x02441453)
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 (0x21e1cde6)
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 (0x455a14ed)
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#define T31 (0x676f02d9)
|
||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||
#define T35 (0x6d9d6122)
|
||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 (0x4bdecfa9)
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 (0x289b7ec6)
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 (0x04881d05)
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 (0x1fa27cf8)
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 (0x432aff97)
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#define T53 (0x655b59c3)
|
||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||
#define T57 (0x6fa87e4f)
|
||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 (0x4e0811a1)
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 (0x2ad7d2bb)
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
static void
|
||||
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
||||
{
|
||||
md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
|
||||
d = pms->abcd[3];
|
||||
md5_word_t t;
|
||||
#if BYTE_ORDER > 0
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
md5_word_t X[16];
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
md5_word_t xbuf[16];
|
||||
const md5_word_t *X;
|
||||
#endif
|
||||
|
||||
{
|
||||
#if BYTE_ORDER == 0
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static const int w = 1;
|
||||
|
||||
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!(((uintptr_t)data) & 3)) {
|
||||
/* data are properly aligned, a direct assignment is possible */
|
||||
/* cast through a (void *) should avoid a compiler warning,
|
||||
see
|
||||
https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861
|
||||
*/
|
||||
X = (const md5_word_t *)(const void *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if BYTE_ORDER == 0
|
||||
else /* dynamic big-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
int i;
|
||||
|
||||
#if BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
#else
|
||||
#define xbuf X /* (static only) */
|
||||
#endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = (md5_word_t)(xp[0]) + (md5_word_t)(xp[1] << 8)
|
||||
+ (md5_word_t)(xp[2] << 16)
|
||||
+ (md5_word_t)(xp[3] << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = (a) + F(b, c, d) + X[k] + (Ti); \
|
||||
(a) = ROTATE_LEFT(t, s) + (b)
|
||||
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = (a) + G(b, c, d) + X[k] + (Ti); \
|
||||
(a) = ROTATE_LEFT(t, s) + (b)
|
||||
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = (a) + H(b, c, d) + X[k] + (Ti); \
|
||||
(a) = ROTATE_LEFT(t, s) + b
|
||||
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = (a) + I(b, c, d) + X[k] + (Ti); \
|
||||
(a) = ROTATE_LEFT(t, s) + (b)
|
||||
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
MD5_STATIC void
|
||||
md5_init(md5_state_t *pms)
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
MD5_STATIC void
|
||||
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
|
||||
{
|
||||
const md5_byte_t *p = data;
|
||||
size_t left = nbytes;
|
||||
size_t offset = (pms->count[0] >> 3) & 63;
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += (md5_word_t)(nbytes >> 29);
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
MD5_STATIC void
|
||||
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
||||
{
|
||||
static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
md5_append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
|
||||
|
||||
/* End of md5.inl */
|
||||
339
components/spotify/cspot/bell/external/civetweb/response.inl
vendored
Normal file
339
components/spotify/cspot/bell/external/civetweb/response.inl
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
/* response.inl
|
||||
*
|
||||
* Bufferring for HTTP headers for HTTP response.
|
||||
* This function are only intended to be used at the server side.
|
||||
* Optional for HTTP/1.0 and HTTP/1.1, mandatory for HTTP/2.
|
||||
*
|
||||
* This file is part of the CivetWeb project.
|
||||
*/
|
||||
|
||||
#if defined(NO_RESPONSE_BUFFERING) && defined(USE_HTTP2)
|
||||
#error "HTTP2 works only if NO_RESPONSE_BUFFERING is not set"
|
||||
#endif
|
||||
|
||||
|
||||
/* Internal function to free header list */
|
||||
static void
|
||||
free_buffered_response_header_list(struct mg_connection *conn)
|
||||
{
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
while (conn->response_info.num_headers > 0) {
|
||||
conn->response_info.num_headers--;
|
||||
mg_free((void *)conn->response_info
|
||||
.http_headers[conn->response_info.num_headers]
|
||||
.name);
|
||||
conn->response_info.http_headers[conn->response_info.num_headers].name =
|
||||
0;
|
||||
mg_free((void *)conn->response_info
|
||||
.http_headers[conn->response_info.num_headers]
|
||||
.value);
|
||||
conn->response_info.http_headers[conn->response_info.num_headers]
|
||||
.value = 0;
|
||||
}
|
||||
#else
|
||||
(void)conn; /* Nothing to do */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Send first line of HTTP/1.x response */
|
||||
static int
|
||||
send_http1_response_status_line(struct mg_connection *conn)
|
||||
{
|
||||
const char *status_txt;
|
||||
const char *http_version = conn->request_info.http_version;
|
||||
int status_code = conn->status_code;
|
||||
|
||||
if ((status_code < 100) || (status_code > 999)) {
|
||||
/* Set invalid status code to "500 Internal Server Error" */
|
||||
status_code = 500;
|
||||
}
|
||||
if (!http_version) {
|
||||
http_version = "1.0";
|
||||
}
|
||||
|
||||
/* mg_get_response_code_text will never return NULL */
|
||||
status_txt = mg_get_response_code_text(conn, conn->status_code);
|
||||
|
||||
if (mg_printf(
|
||||
conn, "HTTP/%s %i %s\r\n", http_version, status_code, status_txt)
|
||||
< 10) {
|
||||
/* Network sending failed */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a new HTTP response
|
||||
* Parameters:
|
||||
* conn: Current connection handle.
|
||||
* status: HTTP status code (e.g., 200 for "OK").
|
||||
* Return:
|
||||
* 0: ok
|
||||
* -1: parameter error
|
||||
* -2: invalid connection type
|
||||
* -3: invalid connection status
|
||||
* -4: network error (only if built with NO_RESPONSE_BUFFERING)
|
||||
*/
|
||||
int
|
||||
mg_response_header_start(struct mg_connection *conn, int status)
|
||||
{
|
||||
int ret = 0;
|
||||
if ((conn == NULL) || (status < 100) || (status > 999)) {
|
||||
/* Parameter error */
|
||||
return -1;
|
||||
}
|
||||
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|
||||
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
|
||||
/* Only allowed in server context */
|
||||
return -2;
|
||||
}
|
||||
if (conn->request_state != 0) {
|
||||
/* only allowed if nothing was sent up to now */
|
||||
return -3;
|
||||
}
|
||||
conn->status_code = status;
|
||||
conn->request_state = 1;
|
||||
|
||||
/* Buffered response is stored, unbuffered response will be sent directly,
|
||||
* but we can only send HTTP/1.x response here */
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
free_buffered_response_header_list(conn);
|
||||
#else
|
||||
if (!send_http1_response_status_line(conn)) {
|
||||
ret = -4;
|
||||
};
|
||||
conn->request_state = 1; /* Reset from 10 to 1 */
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Add a new HTTP response header line
|
||||
* Parameters:
|
||||
* conn: Current connection handle.
|
||||
* header: Header name.
|
||||
* value: Header value.
|
||||
* value_len: Length of header value, excluding the terminating zero.
|
||||
* Use -1 for "strlen(value)".
|
||||
* Return:
|
||||
* 0: ok
|
||||
* -1: parameter error
|
||||
* -2: invalid connection type
|
||||
* -3: invalid connection status
|
||||
* -4: too many headers
|
||||
* -5: out of memory
|
||||
*/
|
||||
int
|
||||
mg_response_header_add(struct mg_connection *conn,
|
||||
const char *header,
|
||||
const char *value,
|
||||
int value_len)
|
||||
{
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
int hidx;
|
||||
#endif
|
||||
|
||||
if ((conn == NULL) || (header == NULL) || (value == NULL)) {
|
||||
/* Parameter error */
|
||||
return -1;
|
||||
}
|
||||
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|
||||
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
|
||||
/* Only allowed in server context */
|
||||
return -2;
|
||||
}
|
||||
if (conn->request_state != 1) {
|
||||
/* only allowed if mg_response_header_start has been called before */
|
||||
return -3;
|
||||
}
|
||||
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
hidx = conn->response_info.num_headers;
|
||||
if (hidx >= MG_MAX_HEADERS) {
|
||||
/* Too many headers */
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Alloc new element */
|
||||
conn->response_info.http_headers[hidx].name =
|
||||
mg_strdup_ctx(header, conn->phys_ctx);
|
||||
if (value_len >= 0) {
|
||||
char *hbuf =
|
||||
(char *)mg_malloc_ctx((unsigned)value_len + 1, conn->phys_ctx);
|
||||
if (hbuf) {
|
||||
memcpy(hbuf, value, (unsigned)value_len);
|
||||
hbuf[value_len] = 0;
|
||||
}
|
||||
conn->response_info.http_headers[hidx].value = hbuf;
|
||||
} else {
|
||||
conn->response_info.http_headers[hidx].value =
|
||||
mg_strdup_ctx(value, conn->phys_ctx);
|
||||
}
|
||||
|
||||
if ((conn->response_info.http_headers[hidx].name == 0)
|
||||
|| (conn->response_info.http_headers[hidx].value == 0)) {
|
||||
/* Out of memory */
|
||||
mg_free((void *)conn->response_info.http_headers[hidx].name);
|
||||
conn->response_info.http_headers[hidx].name = 0;
|
||||
mg_free((void *)conn->response_info.http_headers[hidx].value);
|
||||
conn->response_info.http_headers[hidx].value = 0;
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* OK, header stored */
|
||||
conn->response_info.num_headers++;
|
||||
|
||||
#else
|
||||
if (value_len >= 0) {
|
||||
mg_printf(conn, "%s: %.*s\r\n", header, (int)value_len, value);
|
||||
} else {
|
||||
mg_printf(conn, "%s: %s\r\n", header, value);
|
||||
}
|
||||
conn->request_state = 1; /* Reset from 10 to 1 */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* forward */
|
||||
static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS]);
|
||||
|
||||
|
||||
/* Add a complete header string (key + value).
|
||||
* Parameters:
|
||||
* conn: Current connection handle.
|
||||
* http1_headers: Header line(s) in the form "name: value".
|
||||
* Return:
|
||||
* >=0: no error, number of header lines added
|
||||
* -1: parameter error
|
||||
* -2: invalid connection type
|
||||
* -3: invalid connection status
|
||||
* -4: too many headers
|
||||
* -5: out of memory
|
||||
*/
|
||||
int
|
||||
mg_response_header_add_lines(struct mg_connection *conn,
|
||||
const char *http1_headers)
|
||||
{
|
||||
struct mg_header add_hdr[MG_MAX_HEADERS];
|
||||
int num_hdr, i, ret;
|
||||
char *workbuffer, *parse;
|
||||
|
||||
/* We need to work on a copy of the work buffer, sice parse_http_headers
|
||||
* will modify */
|
||||
workbuffer = mg_strdup_ctx(http1_headers, conn->phys_ctx);
|
||||
if (!workbuffer) {
|
||||
/* Out of memory */
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Call existing method to split header buffer */
|
||||
parse = workbuffer;
|
||||
num_hdr = parse_http_headers(&parse, add_hdr);
|
||||
ret = num_hdr;
|
||||
|
||||
for (i = 0; i < num_hdr; i++) {
|
||||
int lret =
|
||||
mg_response_header_add(conn, add_hdr[i].name, add_hdr[i].value, -1);
|
||||
if ((ret > 0) && (lret < 0)) {
|
||||
/* Store error return value */
|
||||
ret = lret;
|
||||
}
|
||||
}
|
||||
|
||||
/* mg_response_header_add created a copy, so we can free the original */
|
||||
mg_free(workbuffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if defined(USE_HTTP2)
|
||||
static int http2_send_response_headers(struct mg_connection *conn);
|
||||
#endif
|
||||
|
||||
|
||||
/* Send http response
|
||||
* Parameters:
|
||||
* conn: Current connection handle.
|
||||
* Return:
|
||||
* 0: ok
|
||||
* -1: parameter error
|
||||
* -2: invalid connection type
|
||||
* -3: invalid connection status
|
||||
* -4: network send failed
|
||||
*/
|
||||
int
|
||||
mg_response_header_send(struct mg_connection *conn)
|
||||
{
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
int i;
|
||||
int has_date = 0;
|
||||
int has_connection = 0;
|
||||
#endif
|
||||
|
||||
if (conn == NULL) {
|
||||
/* Parameter error */
|
||||
return -1;
|
||||
}
|
||||
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|
||||
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
|
||||
/* Only allowed in server context */
|
||||
return -2;
|
||||
}
|
||||
if (conn->request_state != 1) {
|
||||
/* only allowed if mg_response_header_start has been called before */
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* State: 2 */
|
||||
conn->request_state = 2;
|
||||
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
#if defined(USE_HTTP2)
|
||||
if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) {
|
||||
int ret = http2_send_response_headers(conn);
|
||||
return (ret ? 0 : -4);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Send */
|
||||
if (!send_http1_response_status_line(conn)) {
|
||||
return -4;
|
||||
};
|
||||
for (i = 0; i < conn->response_info.num_headers; i++) {
|
||||
mg_printf(conn,
|
||||
"%s: %s\r\n",
|
||||
conn->response_info.http_headers[i].name,
|
||||
conn->response_info.http_headers[i].value);
|
||||
|
||||
/* Check for some special headers */
|
||||
if (!mg_strcasecmp("Date", conn->response_info.http_headers[i].name)) {
|
||||
has_date = 1;
|
||||
}
|
||||
if (!mg_strcasecmp("Connection",
|
||||
conn->response_info.http_headers[i].name)) {
|
||||
has_connection = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_date) {
|
||||
time_t curtime = time(NULL);
|
||||
char date[64];
|
||||
gmt_time_string(date, sizeof(date), &curtime);
|
||||
mg_printf(conn, "Date: %s\r\n", date);
|
||||
}
|
||||
if (!has_connection) {
|
||||
mg_printf(conn, "Connection: %s\r\n", suggest_connection_header(conn));
|
||||
}
|
||||
#endif
|
||||
|
||||
mg_write(conn, "\r\n", 2);
|
||||
conn->request_state = 3;
|
||||
|
||||
/* ok */
|
||||
return 0;
|
||||
}
|
||||
323
components/spotify/cspot/bell/external/civetweb/sha1.inl
vendored
Normal file
323
components/spotify/cspot/bell/external/civetweb/sha1.inl
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
SHA-1 in C
|
||||
By Steve Reid <sreid@sea-to-sky.net>
|
||||
100% Public Domain
|
||||
|
||||
-----------------
|
||||
Modified 7/98
|
||||
By James H. Brown <jbrown@burgoyne.com>
|
||||
Still 100% Public Domain
|
||||
|
||||
Corrected a problem which generated improper hash values on 16 bit machines
|
||||
Routine SHA1Update changed from
|
||||
void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned int
|
||||
len)
|
||||
to
|
||||
void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned
|
||||
long len)
|
||||
|
||||
The 'len' parameter was declared an int which works fine on 32 bit machines.
|
||||
However, on 16 bit machines an int is too small for the shifts being done
|
||||
against
|
||||
it. This caused the hash function to generate incorrect values if len was
|
||||
greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
|
||||
|
||||
Since the file IO in main() reads 16K at a time, any file 8K or larger would
|
||||
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
|
||||
"a"s).
|
||||
|
||||
I also changed the declaration of variables i & j in SHA1Update to
|
||||
unsigned long from unsigned int for the same reason.
|
||||
|
||||
These changes should make no difference to any 32 bit implementations since
|
||||
an
|
||||
int and a long are the same size in those environments.
|
||||
|
||||
--
|
||||
I also corrected a few compiler warnings generated by Borland C.
|
||||
1. Added #include <process.h> for exit() prototype
|
||||
2. Removed unused variable 'j' in SHA1Final
|
||||
3. Changed exit(0) to return(0) at end of main.
|
||||
|
||||
ALL changes I made can be located by searching for comments containing 'JHB'
|
||||
-----------------
|
||||
Modified 8/98
|
||||
By Steve Reid <sreid@sea-to-sky.net>
|
||||
Still 100% public domain
|
||||
|
||||
1- Removed #include <process.h> and used return() instead of exit()
|
||||
2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
|
||||
3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
|
||||
|
||||
-----------------
|
||||
Modified 4/01
|
||||
By Saul Kravitz <Saul.Kravitz@celera.com>
|
||||
Still 100% PD
|
||||
Modified to run on Compaq Alpha hardware.
|
||||
|
||||
-----------------
|
||||
Modified 07/2002
|
||||
By Ralph Giles <giles@ghostscript.com>
|
||||
Still 100% public domain
|
||||
modified for use with stdint types, autoconf
|
||||
code cleanup, removed attribution comments
|
||||
switched SHA1Final() argument order for consistency
|
||||
use SHA1_ prefix for public api
|
||||
move public api to sha1.h
|
||||
*/
|
||||
|
||||
/*
|
||||
11/2016 adapted for CivetWeb:
|
||||
include sha1.h in sha1.c,
|
||||
rename to sha1.inl
|
||||
remove unused #ifdef sections
|
||||
make endian independent
|
||||
align buffer to 4 bytes
|
||||
remove unused variable assignments
|
||||
*/
|
||||
|
||||
/*
|
||||
Test Vectors (from FIPS PUB 180-1)
|
||||
"abc"
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
A million repetitions of "a"
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t state[5];
|
||||
uint32_t count[2];
|
||||
uint8_t buffer[64];
|
||||
} SHA_CTX;
|
||||
|
||||
#define SHA1_DIGEST_SIZE 20
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
|
||||
|
||||
typedef union {
|
||||
uint8_t c[64];
|
||||
uint32_t l[16];
|
||||
} CHAR64LONG16;
|
||||
|
||||
|
||||
static uint32_t
|
||||
blk0(CHAR64LONG16 *block, int i)
|
||||
{
|
||||
static const uint32_t n = 1u;
|
||||
if ((*((uint8_t *)(&n))) == 1) {
|
||||
/* little endian / intel byte order */
|
||||
block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00)
|
||||
| (rol(block->l[i], 8) & 0x00FF00FF);
|
||||
}
|
||||
return block->l[i];
|
||||
}
|
||||
|
||||
#define blk(block, i) \
|
||||
((block)->l[(i)&15] = \
|
||||
rol((block)->l[((i) + 13) & 15] ^ (block)->l[((i) + 8) & 15] \
|
||||
^ (block)->l[((i) + 2) & 15] ^ (block)->l[(i)&15], \
|
||||
1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v, w, x, y, z, i) \
|
||||
z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
|
||||
w = rol(w, 30);
|
||||
#define R1(v, w, x, y, z, i) \
|
||||
z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5); \
|
||||
w = rol(w, 30);
|
||||
#define R2(v, w, x, y, z, i) \
|
||||
z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5); \
|
||||
w = rol(w, 30);
|
||||
#define R3(v, w, x, y, z, i) \
|
||||
z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 5); \
|
||||
w = rol(w, 30);
|
||||
#define R4(v, w, x, y, z, i) \
|
||||
z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5); \
|
||||
w = rol(w, 30);
|
||||
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
static void
|
||||
SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
||||
{
|
||||
uint32_t a, b, c, d, e;
|
||||
|
||||
/* Must use an aligned, read/write buffer */
|
||||
CHAR64LONG16 block[1];
|
||||
memcpy(block, buffer, sizeof(block));
|
||||
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a, b, c, d, e, 0);
|
||||
R0(e, a, b, c, d, 1);
|
||||
R0(d, e, a, b, c, 2);
|
||||
R0(c, d, e, a, b, 3);
|
||||
R0(b, c, d, e, a, 4);
|
||||
R0(a, b, c, d, e, 5);
|
||||
R0(e, a, b, c, d, 6);
|
||||
R0(d, e, a, b, c, 7);
|
||||
R0(c, d, e, a, b, 8);
|
||||
R0(b, c, d, e, a, 9);
|
||||
R0(a, b, c, d, e, 10);
|
||||
R0(e, a, b, c, d, 11);
|
||||
R0(d, e, a, b, c, 12);
|
||||
R0(c, d, e, a, b, 13);
|
||||
R0(b, c, d, e, a, 14);
|
||||
R0(a, b, c, d, e, 15);
|
||||
R1(e, a, b, c, d, 16);
|
||||
R1(d, e, a, b, c, 17);
|
||||
R1(c, d, e, a, b, 18);
|
||||
R1(b, c, d, e, a, 19);
|
||||
R2(a, b, c, d, e, 20);
|
||||
R2(e, a, b, c, d, 21);
|
||||
R2(d, e, a, b, c, 22);
|
||||
R2(c, d, e, a, b, 23);
|
||||
R2(b, c, d, e, a, 24);
|
||||
R2(a, b, c, d, e, 25);
|
||||
R2(e, a, b, c, d, 26);
|
||||
R2(d, e, a, b, c, 27);
|
||||
R2(c, d, e, a, b, 28);
|
||||
R2(b, c, d, e, a, 29);
|
||||
R2(a, b, c, d, e, 30);
|
||||
R2(e, a, b, c, d, 31);
|
||||
R2(d, e, a, b, c, 32);
|
||||
R2(c, d, e, a, b, 33);
|
||||
R2(b, c, d, e, a, 34);
|
||||
R2(a, b, c, d, e, 35);
|
||||
R2(e, a, b, c, d, 36);
|
||||
R2(d, e, a, b, c, 37);
|
||||
R2(c, d, e, a, b, 38);
|
||||
R2(b, c, d, e, a, 39);
|
||||
R3(a, b, c, d, e, 40);
|
||||
R3(e, a, b, c, d, 41);
|
||||
R3(d, e, a, b, c, 42);
|
||||
R3(c, d, e, a, b, 43);
|
||||
R3(b, c, d, e, a, 44);
|
||||
R3(a, b, c, d, e, 45);
|
||||
R3(e, a, b, c, d, 46);
|
||||
R3(d, e, a, b, c, 47);
|
||||
R3(c, d, e, a, b, 48);
|
||||
R3(b, c, d, e, a, 49);
|
||||
R3(a, b, c, d, e, 50);
|
||||
R3(e, a, b, c, d, 51);
|
||||
R3(d, e, a, b, c, 52);
|
||||
R3(c, d, e, a, b, 53);
|
||||
R3(b, c, d, e, a, 54);
|
||||
R3(a, b, c, d, e, 55);
|
||||
R3(e, a, b, c, d, 56);
|
||||
R3(d, e, a, b, c, 57);
|
||||
R3(c, d, e, a, b, 58);
|
||||
R3(b, c, d, e, a, 59);
|
||||
R4(a, b, c, d, e, 60);
|
||||
R4(e, a, b, c, d, 61);
|
||||
R4(d, e, a, b, c, 62);
|
||||
R4(c, d, e, a, b, 63);
|
||||
R4(b, c, d, e, a, 64);
|
||||
R4(a, b, c, d, e, 65);
|
||||
R4(e, a, b, c, d, 66);
|
||||
R4(d, e, a, b, c, 67);
|
||||
R4(c, d, e, a, b, 68);
|
||||
R4(b, c, d, e, a, 69);
|
||||
R4(a, b, c, d, e, 70);
|
||||
R4(e, a, b, c, d, 71);
|
||||
R4(d, e, a, b, c, 72);
|
||||
R4(c, d, e, a, b, 73);
|
||||
R4(b, c, d, e, a, 74);
|
||||
R4(a, b, c, d, e, 75);
|
||||
R4(e, a, b, c, d, 76);
|
||||
R4(d, e, a, b, c, 77);
|
||||
R4(c, d, e, a, b, 78);
|
||||
R4(b, c, d, e, a, 79);
|
||||
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
}
|
||||
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
SHA_API void
|
||||
SHA1_Init(SHA_CTX *context)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
|
||||
SHA_API void
|
||||
SHA1_Update(SHA_CTX *context, const uint8_t *data, const uint32_t len)
|
||||
{
|
||||
uint32_t i, j;
|
||||
|
||||
j = context->count[0];
|
||||
if ((context->count[0] += (len << 3)) < j) {
|
||||
context->count[1]++;
|
||||
}
|
||||
context->count[1] += (len >> 29);
|
||||
j = (j >> 3) & 63;
|
||||
if ((j + len) > 63) {
|
||||
i = 64 - j;
|
||||
memcpy(&context->buffer[j], data, i);
|
||||
SHA1_Transform(context->state, context->buffer);
|
||||
for (; i + 63 < len; i += 64) {
|
||||
SHA1_Transform(context->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
} else {
|
||||
i = 0;
|
||||
}
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
SHA_API void
|
||||
SHA1_Final(unsigned char *digest, SHA_CTX *context)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t finalcount[8];
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
finalcount[i] =
|
||||
(uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8))
|
||||
& 255); /* Endian independent */
|
||||
}
|
||||
SHA1_Update(context, (uint8_t *)"\x80", 1);
|
||||
while ((context->count[0] & 504) != 448) {
|
||||
SHA1_Update(context, (uint8_t *)"\x00", 1);
|
||||
}
|
||||
SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
|
||||
digest[i] =
|
||||
(uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||
}
|
||||
|
||||
/* Wipe variables */
|
||||
memset(context, '\0', sizeof(*context));
|
||||
}
|
||||
|
||||
|
||||
/* End of sha1.inl */
|
||||
48
components/spotify/cspot/bell/external/civetweb/sort.inl
vendored
Normal file
48
components/spotify/cspot/bell/external/civetweb/sort.inl
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/* Sort function. */
|
||||
/* from https://github.com/bel2125/sort_r */
|
||||
|
||||
static void
|
||||
mg_sort(void *data,
|
||||
size_t elemcount,
|
||||
size_t elemsize,
|
||||
int (*compfunc)(const void *data1, const void *data2, void *userarg),
|
||||
void *userarg)
|
||||
{
|
||||
/* We cannot use qsort_r here. For a detailed reason, see
|
||||
* https://github.com/civetweb/civetweb/issues/1048#issuecomment-1047093014
|
||||
* https://stackoverflow.com/questions/39560773/different-declarations-of-qsort-r-on-mac-and-linux
|
||||
*/
|
||||
|
||||
/* We use ShellSort here with this gap sequence: https://oeis.org/A102549 */
|
||||
int A102549[9] = {1, 4, 10, 23, 57, 132, 301, 701, 1750};
|
||||
int Aidx, gap, i, j, k;
|
||||
void *tmp = alloca(elemsize);
|
||||
|
||||
for (Aidx = 8; Aidx >= 0; Aidx--) {
|
||||
gap = A102549[Aidx];
|
||||
if (gap > ((int)elemcount / 2)) {
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < gap; i++) {
|
||||
for (j = i; j < (int)elemcount; j += gap) {
|
||||
memcpy(tmp, (void *)((ptrdiff_t)data + elemsize * j), elemsize);
|
||||
|
||||
for (k = j; k >= gap; k -= gap) {
|
||||
void *cmp =
|
||||
(void *)((ptrdiff_t)data + elemsize * (k - gap));
|
||||
int cmpres = compfunc(cmp, tmp, userarg);
|
||||
if (cmpres > 0) {
|
||||
memcpy((void *)((ptrdiff_t)data + elemsize * k),
|
||||
cmp,
|
||||
elemsize);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
memcpy((void *)((ptrdiff_t)data + elemsize * k), tmp, elemsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end if sort.inl */
|
||||
Reference in New Issue
Block a user