1
0
mirror of https://github.com/lammertb/libhttp.git synced 2025-09-04 12:42:09 +03:00

Set autoformat options and autoformat all source files

This commit is contained in:
bel
2015-05-17 01:30:21 +02:00
parent 53a18aecf1
commit 6ce8b4e92c
9 changed files with 9603 additions and 9557 deletions

View File

@@ -1,3 +1,14 @@
BasedOnStyle: LLVM # http://clang.llvm.org/docs/ClangFormatStyleOptions.html
IndentWidth: 4
Language: Cpp BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: ForIndentation
ColumnLimit: 80
Language: Cpp
AccessModifierOffset: 2
AlignAfterOpenBracket: true
AllowShortIfStatementsOnASingleLine: false

View File

@@ -21,8 +21,8 @@ class CivetServer;
* Exception class for thrown exceptions within the CivetHandler object. * Exception class for thrown exceptions within the CivetHandler object.
*/ */
class CIVETWEB_API CivetException : public std::runtime_error { class CIVETWEB_API CivetException : public std::runtime_error {
public: public:
CivetException(const std::string &msg) : std::runtime_error(msg) {} CivetException(const std::string &msg) : std::runtime_error(msg) {}
}; };
/** /**
@@ -30,56 +30,56 @@ class CIVETWEB_API CivetException : public std::runtime_error {
* must be reentrant. * must be reentrant.
*/ */
class CIVETWEB_API CivetHandler { class CIVETWEB_API CivetHandler {
public: public:
/** /**
* Destructor * Destructor
*/ */
virtual ~CivetHandler() {} virtual ~CivetHandler() {}
/** /**
* Callback method for GET request. * Callback method for GET request.
* *
* @param server - the calling server * @param server - the calling server
* @param conn - the connection information * @param conn - the connection information
* @returns true if implemented, false otherwise * @returns true if implemented, false otherwise
*/ */
virtual bool handleGet(CivetServer *server, struct mg_connection *conn); virtual bool handleGet(CivetServer *server, struct mg_connection *conn);
/** /**
* Callback method for POST request. * Callback method for POST request.
* *
* @param server - the calling server * @param server - the calling server
* @param conn - the connection information * @param conn - the connection information
* @returns true if implemented, false otherwise * @returns true if implemented, false otherwise
*/ */
virtual bool handlePost(CivetServer *server, struct mg_connection *conn); virtual bool handlePost(CivetServer *server, struct mg_connection *conn);
/** /**
* Callback method for PUT request. * Callback method for PUT request.
* *
* @param server - the calling server * @param server - the calling server
* @param conn - the connection information * @param conn - the connection information
* @returns true if implemented, false otherwise * @returns true if implemented, false otherwise
*/ */
virtual bool handlePut(CivetServer *server, struct mg_connection *conn); virtual bool handlePut(CivetServer *server, struct mg_connection *conn);
/** /**
* Callback method for DELETE request. * Callback method for DELETE request.
* *
* @param server - the calling server * @param server - the calling server
* @param conn - the connection information * @param conn - the connection information
* @returns true if implemented, false otherwise * @returns true if implemented, false otherwise
*/ */
virtual bool handleDelete(CivetServer *server, struct mg_connection *conn); virtual bool handleDelete(CivetServer *server, struct mg_connection *conn);
/** /**
* Callback method for OPTIONS request. * Callback method for OPTIONS request.
* *
* @param server - the calling server * @param server - the calling server
* @param conn - the connection information * @param conn - the connection information
* @returns true if implemented, false otherwise * @returns true if implemented, false otherwise
*/ */
virtual bool handleOptions(CivetServer *server, struct mg_connection *conn); virtual bool handleOptions(CivetServer *server, struct mg_connection *conn);
}; };
/** /**
@@ -88,277 +88,277 @@ class CIVETWEB_API CivetHandler {
* Basic class for embedded web server. This has an URL mapping built-in. * Basic class for embedded web server. This has an URL mapping built-in.
*/ */
class CIVETWEB_API CivetServer { class CIVETWEB_API CivetServer {
public: public:
/** /**
* Constructor * Constructor
* *
* This automatically starts the sever. * This automatically starts the sever.
* It is good practice to call getContext() after this in case there * It is good practice to call getContext() after this in case there
* were errors starting the server. * were errors starting the server.
* *
* @param options - the web server options. * @param options - the web server options.
* @param callbacks - optional web server callback methods. * @param callbacks - optional web server callback methods.
* *
* @throws CivetException * @throws CivetException
*/ */
CivetServer(const char **options, const struct mg_callbacks *callbacks = 0); CivetServer(const char **options, const struct mg_callbacks *callbacks = 0);
/** /**
* Destructor * Destructor
*/ */
virtual ~CivetServer(); virtual ~CivetServer();
/** /**
* close() * close()
* *
* Stops server and frees resources. * Stops server and frees resources.
*/ */
void close(); void close();
/** /**
* getContext() * getContext()
* *
* @return the context or 0 if not running. * @return the context or 0 if not running.
*/ */
const struct mg_context *getContext() const { return context; } const struct mg_context *getContext() const { return context; }
/** /**
* addHandler(const std::string &, CivetHandler *) * addHandler(const std::string &, CivetHandler *)
* *
* Adds a URI handler. If there is existing URI handler, it will * Adds a URI handler. If there is existing URI handler, it will
* be replaced with this one. * be replaced with this one.
* *
* URI's are ordered and prefix (REST) URI's are supported. * URI's are ordered and prefix (REST) URI's are supported.
* *
* @param uri - URI to match. * @param uri - URI to match.
* @param handler - handler instance to use. * @param handler - handler instance to use.
*/ */
void addHandler(const std::string &uri, CivetHandler *handler); void addHandler(const std::string &uri, CivetHandler *handler);
void addHandler(const std::string &uri, CivetHandler &handler) { void addHandler(const std::string &uri, CivetHandler &handler) {
addHandler(uri, &handler); addHandler(uri, &handler);
} }
/** /**
* removeHandler(const std::string &) * removeHandler(const std::string &)
* *
* Removes a handler. * Removes a handler.
* *
* @param uri - the exact URL used in addHandler(). * @param uri - the exact URL used in addHandler().
*/ */
void removeHandler(const std::string &uri); void removeHandler(const std::string &uri);
/** /**
* getListeningPorts() * getListeningPorts()
* *
* Returns a list of ports that are listening * Returns a list of ports that are listening
* *
* @return A vector of ports * @return A vector of ports
*/ */
std::vector<int> getListeningPorts(); std::vector<int> getListeningPorts();
/** /**
* getCookie(struct mg_connection *conn, const std::string &cookieName, * getCookie(struct mg_connection *conn, const std::string &cookieName,
*std::string &cookieValue) *std::string &cookieValue)
* *
* Puts the cookie value string that matches the cookie name in the * Puts the cookie value string that matches the cookie name in the
*cookieValue destinaton string. *cookieValue destinaton string.
* *
* @param conn - the connection information * @param conn - the connection information
* @param cookieName - cookie name to get the value from * @param cookieName - cookie name to get the value from
* @param cookieValue - cookie value is returned using thiis reference * @param cookieValue - cookie value is returned using thiis reference
* @returns the size of the cookie value string read. * @returns the size of the cookie value string read.
*/ */
static int getCookie(struct mg_connection *conn, static int getCookie(struct mg_connection *conn,
const std::string &cookieName, const std::string &cookieName,
std::string &cookieValue); std::string &cookieValue);
/** /**
* getHeader(struct mg_connection *conn, const std::string &headerName) * getHeader(struct mg_connection *conn, const std::string &headerName)
* @param conn - the connection information * @param conn - the connection information
* @param headerName - header name to get the value from * @param headerName - header name to get the value from
* @returns a char array whcih contains the header value as string * @returns a char array whcih contains the header value as string
*/ */
static const char *getHeader(struct mg_connection *conn, static const char *getHeader(struct mg_connection *conn,
const std::string &headerName); const std::string &headerName);
/** /**
* getParam(struct mg_connection *conn, const char *, std::string &, size_t) * getParam(struct mg_connection *conn, const char *, std::string &, size_t)
* *
* Returns a query paramter contained in the supplied buffer. The * Returns a query paramter contained in the supplied buffer. The
* occurance value is a zero-based index of a particular key name. This * occurance 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 * should not be confused with the index over all of the keys. Note that
*this *this
* function assumes that parameters are sent as text in http query string * 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 * format, which is the default for web forms. This function will work for
* html forms with method="GET" and method="POST" attributes. In other * html forms with method="GET" and method="POST" attributes. In other
*cases, *cases,
* you may use a getParam version that directly takes the data instead of * you may use a getParam version that directly takes the data instead of
*the *the
* connection as a first argument. * connection as a first argument.
* *
* @param conn - parameters are read from the data sent through this * @param conn - parameters are read from the data sent through this
*connection *connection
* @param name - the key to search for * @param name - the key to search for
* @param dst - the destination string * @param dst - the destination string
* @param occurrence - the occurrence of the selected name in the query (0 * @param occurrence - the occurrence of the selected name in the query (0
*based). *based).
* @return true if key was found * @return true if key was found
*/ */
static bool getParam(struct mg_connection *conn, const char *name, static bool getParam(struct mg_connection *conn, const char *name,
std::string &dst, size_t occurrence = 0); std::string &dst, size_t occurrence = 0);
/** /**
* getParam(const std::string &, const char *, std::string &, size_t) * getParam(const std::string &, const char *, std::string &, size_t)
* *
* Returns a query paramter contained in the supplied buffer. The * Returns a query paramter contained in the supplied buffer. The
* occurance value is a zero-based index of a particular key name. This * occurance value is a zero-based index of a particular key name. This
* should not be confused with the index over all of the keys. * should not be confused with the index over all of the keys.
* *
* @param data - the query string (text) * @param data - the query string (text)
* @param name - the key to search for * @param name - the key to search for
* @param dst - the destination string * @param dst - the destination string
* @param occurrence - the occurrence of the selected name in the query (0 * @param occurrence - the occurrence of the selected name in the query (0
*based). *based).
* @return true if key was found * @return true if key was found
*/ */
static bool getParam(const std::string &data, const char *name, static bool getParam(const std::string &data, const char *name,
std::string &dst, size_t occurrence = 0) { std::string &dst, size_t occurrence = 0) {
return getParam(data.c_str(), data.length(), name, dst, occurrence); return getParam(data.c_str(), data.length(), name, dst, occurrence);
} }
/** /**
* getParam(const char *, size_t, const char *, std::string &, size_t) * getParam(const char *, size_t, const char *, std::string &, size_t)
* *
* Returns a query paramter contained in the supplied buffer. The * Returns a query paramter contained in the supplied buffer. The
* occurance value is a zero-based index of a particular key name. This * occurance value is a zero-based index of a particular key name. This
* should not be confused with the index over all of the keys. * should not be confused with the index over all of the keys.
* *
* @param data the - query string (text) * @param data the - query string (text)
* @param data_len - length of the query string * @param data_len - length of the query string
* @param name - the key to search for * @param name - the key to search for
* @param dst - the destination string * @param dst - the destination string
* @param occurrence - the occurrence of the selected name in the query (0 * @param occurrence - the occurrence of the selected name in the query (0
*based). *based).
* @return true if key was found * @return true if key was found
*/ */
static bool getParam(const char *data, size_t data_len, const char *name, static bool getParam(const char *data, size_t data_len, const char *name,
std::string &dst, size_t occurrence = 0); std::string &dst, size_t occurrence = 0);
/** /**
* urlDecode(const std::string &, std::string &, bool) * urlDecode(const std::string &, std::string &, bool)
* *
* @param src - string to be decoded * @param src - string to be decoded
* @param dst - destination string * @param dst - destination string
* @param is_form_url_encoded - true if form url encoded * @param is_form_url_encoded - true if form url encoded
* form-url-encoded data differs from URI encoding in a way that it * 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 * uses '+' as character for space, see RFC 1866 section 8.2.1
* http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
*/ */
static void urlDecode(const std::string &src, std::string &dst, static void urlDecode(const std::string &src, std::string &dst,
bool is_form_url_encoded = true) { bool is_form_url_encoded = true) {
urlDecode(src.c_str(), src.length(), dst, is_form_url_encoded); urlDecode(src.c_str(), src.length(), dst, is_form_url_encoded);
} }
/** /**
* urlDecode(const char *, size_t, std::string &, bool) * urlDecode(const char *, size_t, std::string &, bool)
* *
* @param src - buffer to be decoded * @param src - buffer to be decoded
* @param src_len - length of buffer to be decoded * @param src_len - length of buffer to be decoded
* @param dst - destination string * @param dst - destination string
* @param is_form_url_encoded - true if form url encoded * @param is_form_url_encoded - true if form url encoded
* form-url-encoded data differs from URI encoding in a way that it * 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 * uses '+' as character for space, see RFC 1866 section 8.2.1
* http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
*/ */
static void urlDecode(const char *src, size_t src_len, std::string &dst, static void urlDecode(const char *src, size_t src_len, std::string &dst,
bool is_form_url_encoded = true); bool is_form_url_encoded = true);
/** /**
* urlDecode(const char *, std::string &, bool) * urlDecode(const char *, std::string &, bool)
* *
* @param src - buffer to be decoded (0 terminated) * @param src - buffer to be decoded (0 terminated)
* @param dst - destination string * @param dst - destination string
* @param is_form_url_encoded true - if form url encoded * @param is_form_url_encoded true - if form url encoded
* form-url-encoded data differs from URI encoding in a way that it * 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 * uses '+' as character for space, see RFC 1866 section 8.2.1
* http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
*/ */
static void urlDecode(const char *src, std::string &dst, static void urlDecode(const char *src, std::string &dst,
bool is_form_url_encoded = true); bool is_form_url_encoded = true);
/** /**
* urlEncode(const std::string &, std::string &, bool) * urlEncode(const std::string &, std::string &, bool)
* *
* @param src - buffer to be encoded * @param src - buffer to be encoded
* @param dst - destination string * @param dst - destination string
* @param append - true if string should not be cleared before encoding. * @param append - true if string should not be cleared before encoding.
*/ */
static void urlEncode(const std::string &src, std::string &dst, static void urlEncode(const std::string &src, std::string &dst,
bool append = false) { bool append = false) {
urlEncode(src.c_str(), src.length(), dst, append); urlEncode(src.c_str(), src.length(), dst, append);
} }
/** /**
* urlEncode(const char *, size_t, std::string &, bool) * urlEncode(const char *, size_t, std::string &, bool)
* *
* @param src - buffer to be encoded (0 terminated) * @param src - buffer to be encoded (0 terminated)
* @param dst - destination string * @param dst - destination string
* @param append - true if string should not be cleared before encoding. * @param append - true if string should not be cleared before encoding.
*/ */
static void urlEncode(const char *src, std::string &dst, static void urlEncode(const char *src, std::string &dst,
bool append = false); bool append = false);
/** /**
* urlEncode(const char *, size_t, std::string &, bool) * urlEncode(const char *, size_t, std::string &, bool)
* *
* @param src - buffer to be encoded * @param src - buffer to be encoded
* @param src_len - length of buffer to be decoded * @param src_len - length of buffer to be decoded
* @param dst - destination string * @param dst - destination string
* @param append - true if string should not be cleared before encoding. * @param append - true if string should not be cleared before encoding.
*/ */
static void urlEncode(const char *src, size_t src_len, std::string &dst, static void urlEncode(const char *src, size_t src_len, std::string &dst,
bool append = false); bool append = false);
protected: protected:
class CivetConnection { class CivetConnection {
public: public:
char *postData; char *postData;
unsigned long postDataLen; unsigned long postDataLen;
CivetConnection(); CivetConnection();
~CivetConnection(); ~CivetConnection();
}; };
struct mg_context *context; struct mg_context *context;
std::map<struct mg_connection *, class CivetConnection> connections; std::map<struct mg_connection *, class CivetConnection> connections;
private: private:
/** /**
* requestHandler(struct mg_connection *, void *cbdata) * requestHandler(struct mg_connection *, void *cbdata)
* *
* Handles the incomming request. * Handles the incomming request.
* *
* @param conn - the connection information * @param conn - the connection information
* @param cbdata - pointer to the CivetHandler instance. * @param cbdata - pointer to the CivetHandler instance.
* @returns 0 if implemented, false otherwise * @returns 0 if implemented, false otherwise
*/ */
static int requestHandler(struct mg_connection *conn, void *cbdata); static int requestHandler(struct mg_connection *conn, void *cbdata);
/** /**
* closeHandler(struct mg_connection *) * closeHandler(struct mg_connection *)
* *
* Handles closing a request (internal handler) * Handles closing a request (internal handler)
* *
* @param conn - the connection information * @param conn - the connection information
*/ */
static void closeHandler(const struct mg_connection *conn); static void closeHandler(const struct mg_connection *conn);
/** /**
* Stores the user provided close handler * Stores the user provided close handler
*/ */
void (*userCloseHandler)(const struct mg_connection *conn); void (*userCloseHandler)(const struct mg_connection *conn);
}; };
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@@ -51,146 +51,145 @@ struct mg_connection; /* Handle for the individual connection */
/* This structure contains information about the HTTP request. */ /* This structure contains information about the HTTP request. */
struct mg_request_info { struct mg_request_info {
const char *request_method; /* "GET", "POST", etc */ const char *request_method; /* "GET", "POST", etc */
const char *uri; /* URL-decoded URI */ const char *uri; /* URL-decoded URI */
const char *http_version; /* E.g. "1.0", "1.1" */ const char *http_version; /* E.g. "1.0", "1.1" */
const char *query_string; /* URL part after '?', not including '?', or const char *query_string; /* URL part after '?', not including '?', or
NULL */ NULL */
const char *remote_user; /* Authenticated user, or NULL if no auth const char *remote_user; /* Authenticated user, or NULL if no auth
used */ used */
char remote_addr[48]; /* Client's IP address as a string. */ char remote_addr[48]; /* Client's IP address as a string. */
long long remote_ip; /* Client's IP address. Deprecated: use remote_addr instead
remote_ip; /* Client's IP address. Deprecated: use remote_addr instead */
*/
long long content_length; /* Length (in bytes) of the request body, long long content_length; /* Length (in bytes) of the request body,
can be -1 if no length was given. */ can be -1 if no length was given. */
int remote_port; /* Client's port */ int remote_port; /* Client's port */
int is_ssl; /* 1 if SSL-ed, 0 if not */ int is_ssl; /* 1 if SSL-ed, 0 if not */
void *user_data; /* User data pointer passed to mg_start() */ void *user_data; /* User data pointer passed to mg_start() */
void *conn_data; /* Connection-specific user data */ void *conn_data; /* Connection-specific user data */
int num_headers; /* Number of HTTP headers */ int num_headers; /* Number of HTTP headers */
struct mg_header { struct mg_header {
const char *name; /* HTTP header name */ const char *name; /* HTTP header name */
const char *value; /* HTTP header value */ const char *value; /* HTTP header value */
} http_headers[64]; /* Maximum 64 headers */ } http_headers[64]; /* Maximum 64 headers */
}; };
/* This structure needs to be passed to mg_start(), to let civetweb know /* This structure needs to be passed to mg_start(), to let civetweb know
which callbacks to invoke. For a detailed description, see which callbacks to invoke. For a detailed description, see
https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md */ https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md */
struct mg_callbacks { struct mg_callbacks {
/* Called when civetweb has received new HTTP request. /* Called when civetweb has received new HTTP request.
If the callback returns one, it must process the request If the callback returns one, it must process the request
by sending valid HTTP headers and a body. Civetweb will not do by sending valid HTTP headers and a body. Civetweb will not do
any further processing. Otherwise it must return zero. any further processing. Otherwise it must return zero.
Note that since V1.7 the "begin_request" function is called Note that since V1.7 the "begin_request" function is called
before an authorization check. If an authorization check is before an authorization check. If an authorization check is
required, use a request_handler instead. required, use a request_handler instead.
Return value: Return value:
0: civetweb will process the request itself. In this case, 0: civetweb will process the request itself. In this case,
the callback must not send any data to the client. the callback must not send any data to the client.
1: callback already processed the request. Civetweb will 1: callback already processed the request. Civetweb will
not send any data after the callback returned. */ not send any data after the callback returned. */
int (*begin_request)(struct mg_connection *); int (*begin_request)(struct mg_connection *);
/* Called when civetweb has finished processing request. */ /* Called when civetweb has finished processing request. */
void (*end_request)(const struct mg_connection *, int reply_status_code); void (*end_request)(const struct mg_connection *, int reply_status_code);
/* Called when civetweb is about to log a message. If callback returns /* Called when civetweb is about to log a message. If callback returns
non-zero, civetweb does not log anything. */ non-zero, civetweb does not log anything. */
int (*log_message)(const struct mg_connection *, const char *message); int (*log_message)(const struct mg_connection *, const char *message);
/* Called when civetweb is about to log access. If callback returns /* Called when civetweb is about to log access. If callback returns
non-zero, civetweb does not log anything. */ non-zero, civetweb does not log anything. */
int (*log_access)(const struct mg_connection *, const char *message); int (*log_access)(const struct mg_connection *, const char *message);
/* Called when civetweb initializes SSL library. /* Called when civetweb initializes SSL library.
Parameters: Parameters:
user_data: parameter user_data passed when starting the server. user_data: parameter user_data passed when starting the server.
Return value: Return value:
0: civetweb will set up the SSL certificate. 0: civetweb will set up the SSL certificate.
1: civetweb assumes the callback already set up the certificate. 1: civetweb assumes the callback already set up the certificate.
-1: initializing ssl fails. */ -1: initializing ssl fails. */
int (*init_ssl)(void *ssl_context, void *user_data); int (*init_ssl)(void *ssl_context, void *user_data);
/* Called when websocket request is received, before websocket handshake. /* Called when websocket request is received, before websocket handshake.
Return value: Return value:
0: civetweb proceeds with websocket handshake. 0: civetweb proceeds with websocket handshake.
1: connection is closed immediately. 1: connection is closed immediately.
This callback is deprecated, use mg_set_websocket_handler instead. */ This callback is deprecated, use mg_set_websocket_handler instead. */
int (*websocket_connect)(const struct mg_connection *); int (*websocket_connect)(const struct mg_connection *);
/* Called when websocket handshake is successfully completed, and /* Called when websocket handshake is successfully completed, and
connection is ready for data exchange. connection is ready for data exchange.
This callback is deprecated, use mg_set_websocket_handler instead. */ This callback is deprecated, use mg_set_websocket_handler instead. */
void (*websocket_ready)(struct mg_connection *); void (*websocket_ready)(struct mg_connection *);
/* Called when data frame has been received from the client. /* Called when data frame has been received from the client.
Parameters: Parameters:
bits: first byte of the websocket frame, see websocket RFC at bits: first byte of the websocket frame, see websocket RFC at
http://tools.ietf.org/html/rfc6455, section 5.2 http://tools.ietf.org/html/rfc6455, section 5.2
data, data_len: payload, with mask (if any) already applied. data, data_len: payload, with mask (if any) already applied.
Return value: Return value:
1: keep this websocket connection open. 1: keep this websocket connection open.
0: close this websocket connection. 0: close this websocket connection.
This callback is deprecated, use mg_set_websocket_handler instead. */ This callback is deprecated, use mg_set_websocket_handler instead. */
int (*websocket_data)(struct mg_connection *, int bits, char *data, int (*websocket_data)(struct mg_connection *, int bits, char *data,
size_t data_len); size_t data_len);
/* Called when civetweb is closing a connection. The per-context mutex is /* Called when civetweb is closing a connection. The per-context mutex is
locked when this is invoked. This is primarily useful for noting when locked when this is invoked. This is primarily useful for noting when
a websocket is closing and removing it from any application-maintained a websocket is closing and removing it from any application-maintained
list of clients. list of clients.
Using this callback for websocket connections is deprecated, use Using this callback for websocket connections is deprecated, use
mg_set_websocket_handler instead. */ mg_set_websocket_handler instead. */
void (*connection_close)(const struct mg_connection *); void (*connection_close)(const struct mg_connection *);
/* Called when civetweb tries to open a file. Used to intercept file open /* Called when civetweb tries to open a file. Used to intercept file open
calls, and serve file data from memory instead. calls, and serve file data from memory instead.
Parameters: Parameters:
path: Full path to the file to open. path: Full path to the file to open.
data_len: Placeholder for the file size, if file is served from data_len: Placeholder for the file size, if file is served from
memory. memory.
Return value: Return value:
NULL: do not serve file from memory, proceed with normal file open. NULL: do not serve file from memory, proceed with normal file open.
non-NULL: pointer to the file contents in memory. data_len must be non-NULL: pointer to the file contents in memory. data_len must be
initilized with the size of the memory block. */ initilized with the size of the memory block. */
const char *(*open_file)(const struct mg_connection *, const char *path, const char *(*open_file)(const struct mg_connection *, const char *path,
size_t *data_len); size_t *data_len);
/* Called when civetweb is about to serve Lua server page, if /* Called when civetweb is about to serve Lua server page, if
Lua support is enabled. Lua support is enabled.
Parameters: Parameters:
lua_context: "lua_State *" pointer. */ lua_context: "lua_State *" pointer. */
void (*init_lua)(const struct mg_connection *, void *lua_context); void (*init_lua)(const struct mg_connection *, void *lua_context);
/* Called when civetweb has uploaded a file to a temporary directory as a /* Called when civetweb has uploaded a file to a temporary directory as a
result of mg_upload() call. result of mg_upload() call.
Parameters: Parameters:
file_name: full path name to the uploaded file. */ file_name: full path name to the uploaded file. */
void (*upload)(struct mg_connection *, const char *file_name); void (*upload)(struct mg_connection *, const char *file_name);
/* Called when civetweb is about to send HTTP error to the client. /* Called when civetweb is about to send HTTP error to the client.
Implementing this callback allows to create custom error pages. Implementing this callback allows to create custom error pages.
Parameters: Parameters:
status: HTTP error status code. status: HTTP error status code.
Return value: Return value:
1: run civetweb error handler. 1: run civetweb error handler.
0: callback already handled the error. */ 0: callback already handled the error. */
int (*http_error)(struct mg_connection *, int status); int (*http_error)(struct mg_connection *, int status);
/* Called after civetweb context has been created, before requests /* Called after civetweb context has been created, before requests
are processed. are processed.
Parameters: Parameters:
ctx: context handle */ ctx: context handle */
void (*init_context)(const struct mg_context *ctx); void (*init_context)(const struct mg_context *ctx);
/* Called when civetweb context is deleted. /* Called when civetweb context is deleted.
Parameters: Parameters:
ctx: context handle */ ctx: context handle */
void (*exit_context)(const struct mg_context *ctx); void (*exit_context)(const struct mg_context *ctx);
}; };
/* Start web server. /* Start web server.
@@ -347,19 +346,19 @@ CIVETWEB_API const char **mg_get_valid_option_names(void);
#endif #endif
struct mg_option { struct mg_option {
const char *name; const char *name;
int type; int type;
const char *default_value; const char *default_value;
}; };
enum { enum {
CONFIG_TYPE_UNKNOWN = 0x0, CONFIG_TYPE_UNKNOWN = 0x0,
CONFIG_TYPE_NUMBER = 0x1, CONFIG_TYPE_NUMBER = 0x1,
CONFIG_TYPE_STRING = 0x2, CONFIG_TYPE_STRING = 0x2,
CONFIG_TYPE_FILE = 0x3, CONFIG_TYPE_FILE = 0x3,
CONFIG_TYPE_DIRECTORY = 0x4, CONFIG_TYPE_DIRECTORY = 0x4,
CONFIG_TYPE_BOOLEAN = 0x5, CONFIG_TYPE_BOOLEAN = 0x5,
CONFIG_TYPE_EXT_PATTERN = 0x6 CONFIG_TYPE_EXT_PATTERN = 0x6
}; };
/* Return array of struct mg_option, representing all valid configuration /* Return array of struct mg_option, representing all valid configuration
@@ -439,12 +438,12 @@ CIVETWEB_API void mg_unlock_context(struct mg_context *ctx);
/* Opcodes, from http://tools.ietf.org/html/rfc6455 */ /* Opcodes, from http://tools.ietf.org/html/rfc6455 */
enum { enum {
WEBSOCKET_OPCODE_CONTINUATION = 0x0, WEBSOCKET_OPCODE_CONTINUATION = 0x0,
WEBSOCKET_OPCODE_TEXT = 0x1, WEBSOCKET_OPCODE_TEXT = 0x1,
WEBSOCKET_OPCODE_BINARY = 0x2, WEBSOCKET_OPCODE_BINARY = 0x2,
WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8, WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
WEBSOCKET_OPCODE_PING = 0x9, WEBSOCKET_OPCODE_PING = 0x9,
WEBSOCKET_OPCODE_PONG = 0xa WEBSOCKET_OPCODE_PONG = 0xa
}; };
/* Macros for enabling compiler-specific checks for printf-like arguments. */ /* Macros for enabling compiler-specific checks for printf-like arguments. */

View File

@@ -16,288 +16,288 @@
#endif #endif
bool CivetHandler::handleGet(CivetServer *server, struct mg_connection *conn) { bool CivetHandler::handleGet(CivetServer *server, struct mg_connection *conn) {
UNUSED_PARAMETER(server); UNUSED_PARAMETER(server);
UNUSED_PARAMETER(conn); UNUSED_PARAMETER(conn);
return false; return false;
} }
bool CivetHandler::handlePost(CivetServer *server, struct mg_connection *conn) { bool CivetHandler::handlePost(CivetServer *server, struct mg_connection *conn) {
UNUSED_PARAMETER(server); UNUSED_PARAMETER(server);
UNUSED_PARAMETER(conn); UNUSED_PARAMETER(conn);
return false; return false;
} }
bool CivetHandler::handlePut(CivetServer *server, struct mg_connection *conn) { bool CivetHandler::handlePut(CivetServer *server, struct mg_connection *conn) {
UNUSED_PARAMETER(server); UNUSED_PARAMETER(server);
UNUSED_PARAMETER(conn); UNUSED_PARAMETER(conn);
return false; return false;
} }
bool CivetHandler::handleDelete(CivetServer *server, bool CivetHandler::handleDelete(CivetServer *server,
struct mg_connection *conn) { struct mg_connection *conn) {
UNUSED_PARAMETER(server); UNUSED_PARAMETER(server);
UNUSED_PARAMETER(conn); UNUSED_PARAMETER(conn);
return false; return false;
} }
bool CivetHandler::handleOptions(CivetServer *server, bool CivetHandler::handleOptions(CivetServer *server,
struct mg_connection *conn) { struct mg_connection *conn) {
UNUSED_PARAMETER(server); UNUSED_PARAMETER(server);
UNUSED_PARAMETER(conn); UNUSED_PARAMETER(conn);
return false; return false;
} }
int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata) { int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata) {
const struct mg_request_info *request_info = mg_get_request_info(conn); const struct mg_request_info *request_info = mg_get_request_info(conn);
assert(request_info != NULL); assert(request_info != NULL);
CivetServer *me = (CivetServer *)(request_info->user_data); CivetServer *me = (CivetServer *)(request_info->user_data);
assert(me != NULL); assert(me != NULL);
// Happens when a request hits the server before the context is saved // Happens when a request hits the server before the context is saved
if (me->context == NULL) if (me->context == NULL)
return 0; return 0;
mg_lock_context(me->context); mg_lock_context(me->context);
me->connections[conn] = CivetConnection(); me->connections[conn] = CivetConnection();
mg_unlock_context(me->context); mg_unlock_context(me->context);
CivetHandler *handler = (CivetHandler *)cbdata; CivetHandler *handler = (CivetHandler *)cbdata;
if (handler) { if (handler) {
if (strcmp(request_info->request_method, "GET") == 0) { if (strcmp(request_info->request_method, "GET") == 0) {
return handler->handleGet(me, conn) ? 1 : 0; return handler->handleGet(me, conn) ? 1 : 0;
} else if (strcmp(request_info->request_method, "POST") == 0) { } else if (strcmp(request_info->request_method, "POST") == 0) {
return handler->handlePost(me, conn) ? 1 : 0; return handler->handlePost(me, conn) ? 1 : 0;
} else if (strcmp(request_info->request_method, "PUT") == 0) { } else if (strcmp(request_info->request_method, "PUT") == 0) {
return handler->handlePut(me, conn) ? 1 : 0; return handler->handlePut(me, conn) ? 1 : 0;
} else if (strcmp(request_info->request_method, "DELETE") == 0) { } else if (strcmp(request_info->request_method, "DELETE") == 0) {
return handler->handleDelete(me, conn) ? 1 : 0; return handler->handleDelete(me, conn) ? 1 : 0;
} else if (strcmp(request_info->request_method, "OPTIONS") == 0) { } else if (strcmp(request_info->request_method, "OPTIONS") == 0) {
return handler->handleOptions(me, conn) ? 1 : 0; return handler->handleOptions(me, conn) ? 1 : 0;
} }
} }
return 0; // No handler found return 0; // No handler found
} }
CivetServer::CivetServer(const char **options, CivetServer::CivetServer(const char **options,
const struct mg_callbacks *_callbacks) const struct mg_callbacks *_callbacks)
: context(0) { : context(0) {
struct mg_callbacks callbacks; struct mg_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks)); memset(&callbacks, 0, sizeof(callbacks));
if (_callbacks) { if (_callbacks) {
callbacks = *_callbacks; callbacks = *_callbacks;
userCloseHandler = _callbacks->connection_close; userCloseHandler = _callbacks->connection_close;
} else { } else {
userCloseHandler = NULL; userCloseHandler = NULL;
} }
callbacks.connection_close = closeHandler; callbacks.connection_close = closeHandler;
context = mg_start(&callbacks, this, options); context = mg_start(&callbacks, this, options);
if (context == NULL) if (context == NULL)
throw CivetException("null context when constructing CivetServer. " throw CivetException("null context when constructing CivetServer. "
"Possible problem binding to port."); "Possible problem binding to port.");
} }
CivetServer::~CivetServer() { close(); } CivetServer::~CivetServer() { close(); }
void CivetServer::closeHandler(const struct mg_connection *conn) { void CivetServer::closeHandler(const struct mg_connection *conn) {
const struct mg_request_info *request_info = mg_get_request_info(conn); const struct mg_request_info *request_info = mg_get_request_info(conn);
assert(request_info != NULL); assert(request_info != NULL);
CivetServer *me = (CivetServer *)(request_info->user_data); CivetServer *me = (CivetServer *)(request_info->user_data);
assert(me != NULL); assert(me != NULL);
// Happens when a request hits the server before the context is saved // Happens when a request hits the server before the context is saved
if (me->context == NULL) if (me->context == NULL)
return; return;
if (me->userCloseHandler) if (me->userCloseHandler)
me->userCloseHandler(conn); me->userCloseHandler(conn);
mg_lock_context(me->context); mg_lock_context(me->context);
me->connections.erase(const_cast<struct mg_connection *>(conn)); me->connections.erase(const_cast<struct mg_connection *>(conn));
mg_unlock_context(me->context); mg_unlock_context(me->context);
} }
void CivetServer::addHandler(const std::string &uri, CivetHandler *handler) { void CivetServer::addHandler(const std::string &uri, CivetHandler *handler) {
mg_set_request_handler(context, uri.c_str(), requestHandler, handler); mg_set_request_handler(context, uri.c_str(), requestHandler, handler);
} }
void CivetServer::removeHandler(const std::string &uri) { void CivetServer::removeHandler(const std::string &uri) {
mg_set_request_handler(context, uri.c_str(), NULL, NULL); mg_set_request_handler(context, uri.c_str(), NULL, NULL);
} }
void CivetServer::close() { void CivetServer::close() {
if (context) { if (context) {
mg_stop(context); mg_stop(context);
context = 0; context = 0;
} }
} }
int CivetServer::getCookie(struct mg_connection *conn, int CivetServer::getCookie(struct mg_connection *conn,
const std::string &cookieName, const std::string &cookieName,
std::string &cookieValue) { std::string &cookieValue) {
// Maximum cookie length as per microsoft is 4096. // Maximum cookie length as per microsoft is 4096.
// http://msdn.microsoft.com/en-us/library/ms178194.aspx // http://msdn.microsoft.com/en-us/library/ms178194.aspx
char _cookieValue[4096]; char _cookieValue[4096];
const char *cookie = mg_get_header(conn, "Cookie"); const char *cookie = mg_get_header(conn, "Cookie");
int lRead = mg_get_cookie(cookie, cookieName.c_str(), _cookieValue, int lRead = mg_get_cookie(cookie, cookieName.c_str(), _cookieValue,
sizeof(_cookieValue)); sizeof(_cookieValue));
cookieValue.clear(); cookieValue.clear();
cookieValue.append(_cookieValue); cookieValue.append(_cookieValue);
return lRead; return lRead;
} }
const char *CivetServer::getHeader(struct mg_connection *conn, const char *CivetServer::getHeader(struct mg_connection *conn,
const std::string &headerName) { const std::string &headerName) {
return mg_get_header(conn, headerName.c_str()); return mg_get_header(conn, headerName.c_str());
} }
void CivetServer::urlDecode(const char *src, std::string &dst, void CivetServer::urlDecode(const char *src, std::string &dst,
bool is_form_url_encoded) { bool is_form_url_encoded) {
urlDecode(src, strlen(src), dst, 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, void CivetServer::urlDecode(const char *src, size_t src_len, std::string &dst,
bool is_form_url_encoded) { bool is_form_url_encoded) {
int i, j, a, b; int i, j, a, b;
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
dst.clear(); dst.clear();
for (i = j = 0; i < (int)src_len; i++, j++) { for (i = j = 0; i < (int)src_len; i++, j++) {
if (i < (int)src_len - 2 && src[i] == '%' && if (i < (int)src_len - 2 && src[i] == '%' &&
isxdigit(*(const unsigned char *)(src + i + 1)) && isxdigit(*(const unsigned char *)(src + i + 1)) &&
isxdigit(*(const unsigned char *)(src + i + 2))) { isxdigit(*(const unsigned char *)(src + i + 2))) {
a = tolower(*(const unsigned char *)(src + i + 1)); a = tolower(*(const unsigned char *)(src + i + 1));
b = tolower(*(const unsigned char *)(src + i + 2)); b = tolower(*(const unsigned char *)(src + i + 2));
dst.push_back((char)((HEXTOI(a) << 4) | HEXTOI(b))); dst.push_back((char)((HEXTOI(a) << 4) | HEXTOI(b)));
i += 2; i += 2;
} else if (is_form_url_encoded && src[i] == '+') { } else if (is_form_url_encoded && src[i] == '+') {
dst.push_back(' '); dst.push_back(' ');
} else { } else {
dst.push_back(src[i]); dst.push_back(src[i]);
} }
} }
} }
bool CivetServer::getParam(struct mg_connection *conn, const char *name, bool CivetServer::getParam(struct mg_connection *conn, const char *name,
std::string &dst, size_t occurrence) { std::string &dst, size_t occurrence) {
const char *formParams = NULL; const char *formParams = NULL;
const struct mg_request_info *ri = mg_get_request_info(conn); const struct mg_request_info *ri = mg_get_request_info(conn);
assert(ri != NULL); assert(ri != NULL);
CivetServer *me = (CivetServer *)(ri->user_data); CivetServer *me = (CivetServer *)(ri->user_data);
assert(me != NULL); assert(me != NULL);
mg_lock_context(me->context); mg_lock_context(me->context);
CivetConnection &conobj = me->connections[conn]; CivetConnection &conobj = me->connections[conn];
mg_lock_connection(conn); mg_lock_connection(conn);
mg_unlock_context(me->context); mg_unlock_context(me->context);
if (conobj.postData != NULL) { if (conobj.postData != NULL) {
formParams = conobj.postData; formParams = conobj.postData;
} else { } else {
const char *con_len_str = mg_get_header(conn, "Content-Length"); const char *con_len_str = mg_get_header(conn, "Content-Length");
if (con_len_str) { if (con_len_str) {
unsigned long con_len = atoi(con_len_str); unsigned long con_len = atoi(con_len_str);
if (con_len > 0) { if (con_len > 0) {
// Add one extra character: in case the post-data is a text, it // Add one extra character: in case the post-data is a text, it
// is required as 0-termination. // is required as 0-termination.
// Do not increment con_len, since the 0 terminating is not part // Do not increment con_len, since the 0 terminating is not part
// of the content (text or binary). // of the content (text or binary).
conobj.postData = (char *)malloc(con_len + 1); conobj.postData = (char *)malloc(con_len + 1);
if (conobj.postData != NULL) { if (conobj.postData != NULL) {
// malloc may fail for huge requests // malloc may fail for huge requests
mg_read(conn, conobj.postData, con_len); mg_read(conn, conobj.postData, con_len);
conobj.postData[con_len] = 0; conobj.postData[con_len] = 0;
formParams = conobj.postData; formParams = conobj.postData;
conobj.postDataLen = con_len; conobj.postDataLen = con_len;
} }
} }
} }
} }
if (formParams == NULL) { if (formParams == NULL) {
// get requests do store html <form> field values in the http // get requests do store html <form> field values in the http
// query_string // query_string
formParams = ri->query_string; formParams = ri->query_string;
} }
mg_unlock_connection(conn); mg_unlock_connection(conn);
if (formParams != NULL) { if (formParams != NULL) {
return getParam(formParams, strlen(formParams), name, dst, occurrence); return getParam(formParams, strlen(formParams), name, dst, occurrence);
} }
return false; return false;
} }
bool CivetServer::getParam(const char *data, size_t data_len, const char *name, bool CivetServer::getParam(const char *data, size_t data_len, const char *name,
std::string &dst, size_t occurrence) { std::string &dst, size_t occurrence) {
const char *p, *e, *s; const char *p, *e, *s;
size_t name_len; size_t name_len;
dst.clear(); dst.clear();
if (data == NULL || name == NULL || data_len == 0) { if (data == NULL || name == NULL || data_len == 0) {
return false; return false;
} }
name_len = strlen(name); name_len = strlen(name);
e = data + data_len; e = data + data_len;
// data is "var1=val1&var2=val2...". Find variable first // data is "var1=val1&var2=val2...". Find variable first
for (p = data; p + name_len < e; p++) { for (p = data; p + name_len < e; p++) {
if ((p == data || p[-1] == '&') && p[name_len] == '=' && if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
!mg_strncasecmp(name, p, name_len) && 0 == occurrence--) { !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
// Point p to variable value // Point p to variable value
p += name_len + 1; p += name_len + 1;
// Point s to the end of the value // Point s to the end of the value
s = (const char *)memchr(p, '&', (size_t)(e - p)); s = (const char *)memchr(p, '&', (size_t)(e - p));
if (s == NULL) { if (s == NULL) {
s = e; s = e;
} }
assert(s >= p); assert(s >= p);
// Decode variable into destination buffer // Decode variable into destination buffer
urlDecode(p, (int)(s - p), dst, true); urlDecode(p, (int)(s - p), dst, true);
return true; return true;
} }
} }
return false; return false;
} }
void CivetServer::urlEncode(const char *src, std::string &dst, bool append) { void CivetServer::urlEncode(const char *src, std::string &dst, bool append) {
urlEncode(src, strlen(src), dst, append); urlEncode(src, strlen(src), dst, append);
} }
void CivetServer::urlEncode(const char *src, size_t src_len, std::string &dst, void CivetServer::urlEncode(const char *src, size_t src_len, std::string &dst,
bool append) { bool append) {
static const char *dont_escape = "._-$,;~()"; static const char *dont_escape = "._-$,;~()";
static const char *hex = "0123456789abcdef"; static const char *hex = "0123456789abcdef";
if (!append) if (!append)
dst.clear(); dst.clear();
for (; src_len > 0; src++, src_len--) { for (; src_len > 0; src++, src_len--) {
if (isalnum(*(const unsigned char *)src) || if (isalnum(*(const unsigned char *)src) ||
strchr(dont_escape, *(const unsigned char *)src) != NULL) { strchr(dont_escape, *(const unsigned char *)src) != NULL) {
dst.push_back(*src); dst.push_back(*src);
} else { } else {
dst.push_back('%'); dst.push_back('%');
dst.push_back(hex[(*(const unsigned char *)src) >> 4]); dst.push_back(hex[(*(const unsigned char *)src) >> 4]);
dst.push_back(hex[(*(const unsigned char *)src) & 0xf]); dst.push_back(hex[(*(const unsigned char *)src) & 0xf]);
} }
} }
} }
std::vector<int> CivetServer::getListeningPorts() { std::vector<int> CivetServer::getListeningPorts() {
std::vector<int> ports(10); std::vector<int> ports(10);
std::vector<int> ssl(10); std::vector<int> ssl(10);
size_t size = mg_get_ports(context, ports.size(), &ports[0], &ssl[0]); size_t size = mg_get_ports(context, ports.size(), &ports[0], &ssl[0]);
ports.resize(size); ports.resize(size);
ssl.resize(size); ssl.resize(size);
return ports; return ports;
} }
CivetServer::CivetConnection::CivetConnection() { CivetServer::CivetConnection::CivetConnection() {
postData = NULL; postData = NULL;
postDataLen = 0; postDataLen = 0;
} }
CivetServer::CivetConnection::~CivetConnection() { free(postData); } CivetServer::CivetConnection::~CivetConnection() { free(postData); }

File diff suppressed because it is too large Load Diff

2596
src/main.c

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@
*/ */
#ifndef md5_INCLUDED #ifndef md5_INCLUDED
# define md5_INCLUDED #define md5_INCLUDED
/* /*
* This package supports both compile-time and run-time determination of CPU * This package supports both compile-time and run-time determination of CPU
@@ -48,31 +48,31 @@
*/ */
typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */ typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */ /* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s { typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */ md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */ md5_byte_t buf[64]; /* accumulate block */
} md5_state_t; } md5_state_t;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
/* Initialize the algorithm. */ /* Initialize the algorithm. */
MD5_STATIC void md5_init(md5_state_t *pms); MD5_STATIC void md5_init(md5_state_t *pms);
/* Append a string to the message. */ /* Append a string to the message. */
MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data,
int nbytes);
/* Finish the message and return the digest. */ /* Finish the message and return the digest. */
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#ifdef __cplusplus #ifdef __cplusplus
} /* end extern "C" */ } /* end extern "C" */
#endif #endif
#endif /* md5_INCLUDED */ #endif /* md5_INCLUDED */
@@ -134,330 +134,321 @@ MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#include <string.h> #include <string.h>
#endif #endif
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN #ifdef ARCH_IS_BIG_ENDIAN
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else #else
# define BYTE_ORDER 0 #define BYTE_ORDER 0
#endif #endif
#define T_MASK ((md5_word_t)~0) #define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db #define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a #define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8 #define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122 #define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821 #define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51 #define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453 #define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6 #define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed #define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9 #define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122 #define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9 #define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6 #define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05 #define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8 #define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97 #define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3 #define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f #define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1 #define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb #define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) {
static void md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) d = pms->abcd[3];
{ md5_word_t t;
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 #if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */ /* Define storage only for big-endian CPUs. */
md5_word_t X[16]; md5_word_t X[16];
#else #else
/* Define storage for little-endian or both types of CPUs. */ /* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16]; md5_word_t xbuf[16];
const md5_word_t *X; const md5_word_t *X;
#endif #endif
{ {
#if BYTE_ORDER == 0 #if BYTE_ORDER == 0
/* /*
* Determine dynamically whether this is a big-endian or * Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient * little-endian machine, since we can use a more efficient
* algorithm on the latter. * algorithm on the latter.
*/ */
static const int w = 1; static const int w = 1;
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
#endif #endif
#if BYTE_ORDER <= 0 /* little-endian */ #if BYTE_ORDER <= 0 /* little-endian */
{ {
/* /*
* On little-endian machines, we can process properly aligned * On little-endian machines, we can process properly aligned
* data without copying it. * data without copying it.
*/ */
if (!((data - (const md5_byte_t *)0) & 3)) { if (!((data - (const md5_byte_t *)0) & 3)) {
/* data are properly aligned, a direct assignment is possible */ /* data are properly aligned, a direct assignment is possible */
/* cast through a (void *) should avoid a compiler warning, /* cast through a (void *) should avoid a compiler warning,
see https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861 */ see
X = (const md5_word_t *)(void *)data; https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861
} else { */
/* not aligned */ X = (const md5_word_t *)(void *)data;
memcpy(xbuf, data, 64); } else {
X = xbuf; /* not aligned */
} memcpy(xbuf, data, 64);
} X = xbuf;
}
}
#endif #endif
#if BYTE_ORDER == 0 #if BYTE_ORDER == 0
else /* dynamic big-endian */ else /* dynamic big-endian */
#endif #endif
#if BYTE_ORDER >= 0 /* big-endian */ #if BYTE_ORDER >= 0 /* big-endian */
{ {
/* /*
* On big-endian machines, we must arrange the bytes in the * On big-endian machines, we must arrange the bytes in the
* right order. * right order.
*/ */
const md5_byte_t *xp = data; const md5_byte_t *xp = data;
int i; int i;
# if BYTE_ORDER == 0 #if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */ X = xbuf; /* (dynamic only) */
# else #else
# define xbuf X /* (static only) */ #define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif #endif
} for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */ /* Round 1. */
/* Let [abcd k s i] denote the operation /* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\ #define SET(a, b, c, d, k, s, Ti) \
t = a + F(b,c,d) + X[k] + Ti;\ t = a + F(b, c, d) + X[k] + Ti; \
a = ROTATE_LEFT(t, s) + b a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */ /* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1); SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2); SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3); SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4); SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5); SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6); SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7); SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8); SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9); SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10); SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11); SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12); SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13); SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14); SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15); SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16); SET(b, c, d, a, 15, 22, T16);
#undef SET #undef SET
/* Round 2. */ /* Round 2. */
/* Let [abcd k s i] denote the operation /* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\ #define SET(a, b, c, d, k, s, Ti) \
t = a + G(b,c,d) + X[k] + Ti;\ t = a + G(b, c, d) + X[k] + Ti; \
a = ROTATE_LEFT(t, s) + b a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */ /* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17); SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18); SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19); SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20); SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21); SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22); SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23); SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24); SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25); SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26); SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27); SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28); SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29); SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30); SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31); SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32); SET(b, c, d, a, 12, 20, T32);
#undef SET #undef SET
/* Round 3. */ /* Round 3. */
/* Let [abcd k s t] denote the operation /* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z)) #define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\ #define SET(a, b, c, d, k, s, Ti) \
t = a + H(b,c,d) + X[k] + Ti;\ t = a + H(b, c, d) + X[k] + Ti; \
a = ROTATE_LEFT(t, s) + b a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */ /* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33); SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34); SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35); SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36); SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37); SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38); SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39); SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40); SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41); SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42); SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43); SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44); SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45); SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46); SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47); SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48); SET(b, c, d, a, 2, 23, T48);
#undef SET #undef SET
/* Round 4. */ /* Round 4. */
/* Let [abcd k s t] denote the operation /* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z))) #define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\ #define SET(a, b, c, d, k, s, Ti) \
t = a + I(b,c,d) + X[k] + Ti;\ t = a + I(b, c, d) + X[k] + Ti; \
a = ROTATE_LEFT(t, s) + b a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */ /* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49); SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50); SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51); SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52); SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53); SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54); SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55); SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56); SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57); SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58); SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59); SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60); SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61); SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62); SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63); SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64); SET(b, c, d, a, 9, 21, T64);
#undef SET #undef SET
/* Then perform the following additions. (That is increment each /* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block of the four registers by the value it had before this block
was started.) */ was started.) */
pms->abcd[0] += a; pms->abcd[0] += a;
pms->abcd[1] += b; pms->abcd[1] += b;
pms->abcd[2] += c; pms->abcd[2] += c;
pms->abcd[3] += d; pms->abcd[3] += d;
} }
MD5_STATIC void MD5_STATIC void md5_init(md5_state_t *pms) {
md5_init(md5_state_t *pms) pms->count[0] = pms->count[1] = 0;
{ pms->abcd[0] = 0x67452301;
pms->count[0] = pms->count[1] = 0; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[0] = 0x67452301; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[3] = 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
} }
MD5_STATIC void MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data,
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) int nbytes) {
{ const md5_byte_t *p = data;
const md5_byte_t *p = data; int left = nbytes;
int left = nbytes; int offset = (pms->count[0] >> 3) & 63;
int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3);
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0) if (nbytes <= 0)
return; return;
/* Update the message length. */ /* Update the message length. */
pms->count[1] += nbytes >> 29; pms->count[1] += nbytes >> 29;
pms->count[0] += nbits; pms->count[0] += nbits;
if (pms->count[0] < nbits) if (pms->count[0] < nbits)
pms->count[1]++; pms->count[1]++;
/* Process an initial partial block. */ /* Process an initial partial block. */
if (offset) { if (offset) {
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy); memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64) if (offset + copy < 64)
return; return;
p += copy; p += copy;
left -= copy; left -= copy;
md5_process(pms, pms->buf); md5_process(pms, pms->buf);
} }
/* Process full blocks. */ /* Process full blocks. */
for (; left >= 64; p += 64, left -= 64) for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p); md5_process(pms, p);
/* Process a final partial block. */ /* Process a final partial block. */
if (left) if (left)
memcpy(pms->buf, p, left); memcpy(pms->buf, p, left);
} }
MD5_STATIC void MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) {
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,
static const md5_byte_t pad[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, md5_byte_t data[8];
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, int i;
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. */ /* Save the length before padding. */
for (i = 0; i < 8; ++i) for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */ /* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */ /* Append the length. */
md5_append(pms, data, 8); md5_append(pms, data, 8);
for (i = 0; i < 16; ++i) for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,131 +1,128 @@
#if !defined(MAX_TIMERS)
#define MAX_TIMERS MAX_WORKER_THREADS
#endif
typedef int (*taction)(void *arg);
struct ttimer {
double time;
double period;
taction action;
void * arg;
};
struct ttimers {
pthread_t threadid; /* Timer thread ID */
pthread_mutex_t mutex; /* Protects timer lists */
struct ttimer timers[MAX_TIMERS]; /* List of timers */
unsigned timer_count; /* Current size of timer list */
};
static int timer_add(struct mg_context * ctx, double next_time, double period, int is_relative, taction action, void * arg) #if !defined(MAX_TIMERS)
{ #define MAX_TIMERS MAX_WORKER_THREADS
unsigned u, v;
int error = 0;
struct timespec now;
if (ctx->stop_flag) {
return 0;
}
if (is_relative) {
clock_gettime(CLOCK_MONOTONIC, &now);
next_time += now.tv_sec;
next_time += now.tv_nsec * 1.0E-9;
}
pthread_mutex_lock(&ctx->timers->mutex);
if (ctx->timers->timer_count == MAX_TIMERS) {
error = 1;
} else {
for (u=0; u<ctx->timers->timer_count; u++) {
if (ctx->timers->timers[u].time < next_time) {
for (v=ctx->timers->timer_count; v>u; v--) {
ctx->timers->timers[v] = ctx->timers->timers[v-1];
}
break;
}
}
ctx->timers->timers[u].time = next_time;
ctx->timers->timers[u].period = period;
ctx->timers->timers[u].action = action;
ctx->timers->timers[u].arg = arg;
ctx->timers->timer_count++;
}
pthread_mutex_unlock(&ctx->timers->mutex);
return error;
}
static void timer_thread_run(void *thread_func_param)
{
struct mg_context *ctx = (struct mg_context *) thread_func_param;
struct timespec now;
double d;
unsigned u;
int re_schedule;
struct ttimer t;
#if defined(HAVE_CLOCK_NANOSLEEP) /* Linux with librt */
/* TODO */
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &request, &request)==EINTR) {/*nop*/;}
#else
clock_gettime(CLOCK_MONOTONIC, &now);
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
while (ctx->stop_flag == 0) {
pthread_mutex_lock(&ctx->timers->mutex);
if (ctx->timers->timer_count > 0 && d >= ctx->timers->timers[0].time) {
t = ctx->timers->timers[0];
for (u=1; u<ctx->timers->timer_count; u++) {
ctx->timers->timers[u-1] = ctx->timers->timers[u];
}
ctx->timers->timer_count--;
pthread_mutex_unlock(&ctx->timers->mutex);
re_schedule = t.action(t.arg);
if (re_schedule && (t.period>0)) {
timer_add(ctx, t.time+t.period, t.period, 0, t.action, t.arg);
}
continue;
} else {
pthread_mutex_unlock(&ctx->timers->mutex);
}
mg_sleep(1);
clock_gettime(CLOCK_MONOTONIC, &now);
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
}
#endif #endif
typedef int (*taction)(void *arg);
struct ttimer {
double time;
double period;
taction action;
void *arg;
};
struct ttimers {
pthread_t threadid; /* Timer thread ID */
pthread_mutex_t mutex; /* Protects timer lists */
struct ttimer timers[MAX_TIMERS]; /* List of timers */
unsigned timer_count; /* Current size of timer list */
};
static int timer_add(struct mg_context *ctx, double next_time, double period,
int is_relative, taction action, void *arg) {
unsigned u, v;
int error = 0;
struct timespec now;
if (ctx->stop_flag) {
return 0;
}
if (is_relative) {
clock_gettime(CLOCK_MONOTONIC, &now);
next_time += now.tv_sec;
next_time += now.tv_nsec * 1.0E-9;
}
pthread_mutex_lock(&ctx->timers->mutex);
if (ctx->timers->timer_count == MAX_TIMERS) {
error = 1;
} else {
for (u = 0; u < ctx->timers->timer_count; u++) {
if (ctx->timers->timers[u].time < next_time) {
for (v = ctx->timers->timer_count; v > u; v--) {
ctx->timers->timers[v] = ctx->timers->timers[v - 1];
}
break;
}
}
ctx->timers->timers[u].time = next_time;
ctx->timers->timers[u].period = period;
ctx->timers->timers[u].action = action;
ctx->timers->timers[u].arg = arg;
ctx->timers->timer_count++;
}
pthread_mutex_unlock(&ctx->timers->mutex);
return error;
}
static void timer_thread_run(void *thread_func_param) {
struct mg_context *ctx = (struct mg_context *)thread_func_param;
struct timespec now;
double d;
unsigned u;
int re_schedule;
struct ttimer t;
#if defined(HAVE_CLOCK_NANOSLEEP) /* Linux with librt */
/* TODO */
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &request,
&request) == EINTR) { /*nop*/
;
}
#else
clock_gettime(CLOCK_MONOTONIC, &now);
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
while (ctx->stop_flag == 0) {
pthread_mutex_lock(&ctx->timers->mutex);
if (ctx->timers->timer_count > 0 && d >= ctx->timers->timers[0].time) {
t = ctx->timers->timers[0];
for (u = 1; u < ctx->timers->timer_count; u++) {
ctx->timers->timers[u - 1] = ctx->timers->timers[u];
}
ctx->timers->timer_count--;
pthread_mutex_unlock(&ctx->timers->mutex);
re_schedule = t.action(t.arg);
if (re_schedule && (t.period > 0)) {
timer_add(ctx, t.time + t.period, t.period, 0, t.action, t.arg);
}
continue;
} else {
pthread_mutex_unlock(&ctx->timers->mutex);
}
mg_sleep(1);
clock_gettime(CLOCK_MONOTONIC, &now);
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
}
#endif
} }
#ifdef _WIN32 #ifdef _WIN32
static unsigned __stdcall timer_thread(void *thread_func_param) static unsigned __stdcall timer_thread(void *thread_func_param) {
{ timer_thread_run(thread_func_param);
timer_thread_run(thread_func_param); return 0;
return 0;
} }
#else #else
static void *timer_thread(void *thread_func_param) static void *timer_thread(void *thread_func_param) {
{ timer_thread_run(thread_func_param);
timer_thread_run(thread_func_param); return NULL;
return NULL;
} }
#endif /* _WIN32 */ #endif /* _WIN32 */
static int timers_init(struct mg_context * ctx) static int timers_init(struct mg_context *ctx) {
{ ctx->timers = (struct ttimers *)mg_calloc(sizeof(struct ttimers), 1);
ctx->timers = (struct ttimers*) mg_calloc(sizeof(struct ttimers), 1); (void)pthread_mutex_init(&ctx->timers->mutex, NULL);
(void) pthread_mutex_init(&ctx->timers->mutex, NULL);
/* Start timer thread */ /* Start timer thread */
mg_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid); mg_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid);
return 0; return 0;
} }
static void timers_exit(struct mg_context * ctx) static void timers_exit(struct mg_context *ctx) {
{ if (ctx->timers) {
if (ctx->timers) { (void)pthread_mutex_destroy(&ctx->timers->mutex);
(void) pthread_mutex_destroy(&ctx->timers->mutex); mg_free(ctx->timers);
mg_free(ctx->timers); }
}
} }