27 #include <microhttpd.h>
35 #define GNUNET_REST_SERVICE_PORT 7776
41 #define MAX_HTTP_URI_LENGTH 2048
51 #define HTTPS_PORT 443
56 #define MHD_CACHE_TIMEOUT \
57 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
59 #define GN_REST_STATE_INIT 0
60 #define GN_REST_STATE_PROCESSING 1
189 struct MHD_Connection *
con;
195 struct MHD_PostProcessor *
pp;
285 MHD_resume_connection (
handle->con);
300 if (NULL !=
handle->response)
301 MHD_destroy_response (
handle->response);
302 if (NULL !=
handle->data_handle)
304 if (NULL !=
handle->data_handle->header_param_map)
311 handle->data_handle->header_param_map);
313 if (NULL !=
handle->data_handle->url_param_map)
319 handle->data_handle->url_param_map);
349 enum MHD_ValueKind kind,
369 "Could not load add header `%s'=%s\n",
380 enum MHD_ValueKind kind,
397 "Could not load add url param `%s'=%s\n",
407 enum MHD_ValueKind kind,
410 const char *content_type,
411 const char *transfer_encoding,
420 if (MHD_POSTDATA_KIND != kind)
436 "Could not add url param '%s'\n",
473 struct MHD_Connection *con,
477 const char *upload_data,
478 size_t *upload_data_size,
501 con_handle->
con = con;
510 rest_conndata_handle->
method = meth;
511 rest_conndata_handle->
url = url;
512 rest_conndata_handle->
data = upload_data;
513 rest_conndata_handle->
data_size = *upload_data_size;
519 MHD_get_connection_values (con,
520 MHD_GET_ARGUMENT_KIND,
522 rest_conndata_handle);
523 MHD_get_connection_values (con,
526 rest_conndata_handle);
530 user = MHD_basic_auth_get_username_password (con, &pw);
531 if ((NULL == user) ||
532 (0 != strcmp (user,
cuser)))
535 "Unknown user %s\n", user);
543 "Password incorrect\n");
551 con_handle->
pp = MHD_create_post_processor (con,
554 rest_conndata_handle);
555 if (*upload_data_size)
557 MHD_post_process (con_handle->
pp, upload_data, *upload_data_size);
559 MHD_destroy_post_processor (con_handle->
pp);
574 *upload_data_size = 0;
581 MHD_suspend_connection (con_handle->
con);
586 "Queueing response from plugin with MHD\n");
600 strncmp (
"moz-extension://",
origin, strlen (
"moz-extension://"))) ||
601 (0 == strncmp (
"chrome-extension://",
603 strlen (
"chrome-extension://"))))
606 MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
613 char *allow_origin = strtok (tmp,
",");
614 while (NULL != allow_origin)
616 if (0 == strncmp (allow_origin,
origin, strlen (allow_origin)))
619 MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
623 allow_origin = strtok (NULL,
",");
631 "Access-Control-Allow-Credentials",
637 "Access-Control-Allow-Headers",
662 MHD_stop_daemon (
httpd);
711 MHD_UNSIGNED_LONG_LONG
timeout;
718 if (MHD_YES != MHD_get_fdset (
httpd, &rs, &ws, &es, &
max))
724 if (MHD_YES == haveto)
745 if ((MHD_YES == haveto) || (-1 !=
max))
776 struct MHD_Connection *connection)
779 const union MHD_ConnectionInfo *ci;
781 ci = MHD_get_connection_info (connection,
782 MHD_CONNECTION_INFO_SOCKET_CONTEXT);
789 ar = ci->socket_context;
806 struct MHD_Connection *connection,
808 enum MHD_RequestTerminationCode toe)
811 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
813 "MHD encountered error handling request: %d\n",
837 struct MHD_Connection *connection,
839 enum MHD_ConnectionNotificationCode cnc)
842 const union MHD_ConnectionInfo *ci;
847 case MHD_CONNECTION_NOTIFY_STARTED:
849 ci = MHD_get_connection_info (connection,
850 MHD_CONNECTION_INFO_CONNECTION_FD);
856 sock = ci->connect_fd;
869 case MHD_CONNECTION_NOTIFY_CLOSED:
871 "Connection closed... cleaning up\n");
876 "Connection stale!\n");
915 const struct sockaddr *addr;
938 if (NULL == ar->
sock)
945 "Got an inbound connection, waiting for data\n");
952 if (MHD_YES != MHD_add_connection (
httpd, fd, addr,
len))
957 _ (
"Failed to pass client to MHD\n"));
1000 struct sockaddr_in sa4;
1003 memset (&sa4, 0,
sizeof(sa4));
1004 sa4.sin_family = AF_INET;
1005 sa4.sin_port = htons (
port);
1006 sa4.sin_addr.s_addr =
address;
1007 #if HAVE_SOCKADDR_IN_SIN_LEN
1008 sa4.sin_len =
sizeof(sa4);
1014 (
const struct sockaddr *) &sa4,
1035 struct sockaddr_in6 sa6;
1038 memset (&sa6, 0,
sizeof(sa6));
1039 sa6.sin6_family = AF_INET6;
1040 sa6.sin6_port = htons (
port);
1042 #if HAVE_SOCKADDR_IN_SIN_LEN
1043 sa6.sin6_len =
sizeof(sa6);
1049 (
const struct sockaddr *) &sa6,
1074 if (NULL == lib_ret)
1077 "Could not load plugin `%s'\n",
1104 const char *cfgfile,
1108 char *basic_auth_file;
1132 if (1 != inet_pton (AF_INET, addr_str, &
address))
1135 "Unable to parse address %s\n",
1153 if (1 != inet_pton (AF_INET6, addr_str, &
address6))
1156 "Unable to parse IPv6 address %s\n",
1166 "BASIC_AUTH_ENABLED");
1171 "BASIC_AUTH_SECRET_FILE",
1175 "No basic auth secret file location set...\n");
1182 "No basic auth secret found... generating\n");
1200 char basic_auth_secret_tmp[16];
1201 memset (basic_auth_secret_tmp, 0, 16);
1203 basic_auth_secret_tmp,
1204 sizeof (basic_auth_secret_tmp) - 1))
1207 "Unable to read basic auth secret file.\n");
1213 if (0 != getlogin_r (
cuser, _POSIX_LOGIN_NAME_MAX))
1216 "Unable to get user.\n");
1228 "REST_ECHO_ORIGIN_WEBEXT");
1232 "REST_ALLOW_ORIGIN",
1236 "No CORS Access-Control-Allow-Origin header will be sent...\n");
1241 "REST_ALLOW_CREDENTIALS",
1246 "No CORS Credential Header will be sent...\n");
1251 "REST_ALLOW_HEADERS",
1256 "No CORS Access-Control-Allow-Headers Header will be sent...\n");
1309 httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
1310 | MHD_ALLOW_SUSPEND_RESUME,
1316 MHD_OPTION_CONNECTION_TIMEOUT,
1318 MHD_OPTION_NOTIFY_CONNECTION,
1321 MHD_OPTION_URI_LOG_CALLBACK,
1324 MHD_OPTION_NOTIFY_COMPLETED,
1335 "libgnunet_plugin_rest",
1357 static const char *err_page =
"{}";
1365 MHD_RESPMEM_PERSISTENT);
1368 "gnunet-rest-server",
1369 _ (
"GNUnet REST server"),
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
struct GNUNET_GETOPT_CommandLineOption options[]
static int ret
Return value of the commandline.
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
struct TestcasePlugin * plugin
The process handle to the testbed service.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
uint32_t data
The data value.
uint16_t status
See PRISM_STATUS_*-constants.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
static char origin[GNUNET_DNSPARSER_MAX_NAME_LENGTH]
Current origin.
static char * value
Value of the record to add/remove.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
static char * allow_origins
Allowed Origins (CORS)
static void plugin_callback(void *cls, struct MHD_Response *resp, int status)
Plugin result callback.
#define GNUNET_REST_SERVICE_PORT
Default Socks5 listen port.
static struct AcceptedRequest * req_list_head
AcceptedRequest list head.
static void * mhd_log_callback(void *cls, const char *url, struct MHD_Connection *connection)
Function called when MHD first processes an incoming connection.
static int basic_auth_enabled
Do basic auth of user.
static struct GNUNET_NETWORK_Handle * bind_v6()
Create an IPv6 listen socket bound to our port.
static void run_mhd_now()
Run MHD now, we have extra data ready for the callback.
static struct MHD_Daemon * httpd
Daemon for HTTP.
char cuser[_POSIX_LOGIN_NAME_MAX]
User of the service.
static MHD_RESULT post_data_iter(void *cls, enum MHD_ValueKind kind, const char *key, const char *filename, const char *content_type, const char *transfer_encoding, const char *data, uint64_t off, size_t size)
static struct GNUNET_NETWORK_Handle * lsock6
The listen socket of the service for IPv6.
#define GN_REST_STATE_INIT
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static char * allow_headers
Allowed Headers (CORS)
static char * basic_auth_secret
Basic auth secret.
static MHD_RESULT create_response(void *cls, struct MHD_Connection *con, const char *url, const char *meth, const char *ver, const char *upload_data, size_t *upload_data_size, void **con_cls)
Main MHD callback for handling requests.
static struct GNUNET_NETWORK_Handle * lsock4
The listen socket of the service for IPv4.
static void kill_httpd()
Kill the MHD daemon.
static struct in6_addr address6
The IPv6 address to bind to.
static unsigned long long port
The port the service is running on (default 7776)
#define GN_REST_STATE_PROCESSING
static void do_shutdown(void *cls)
Task run on shutdown.
static void cleanup_ar(struct AcceptedRequest *ar)
static void mhd_completed_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
Function called when MHD decides that we are done with a connection.
static int url_iterator(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
static int cleanup_url_map(void *cls, const struct GNUNET_HashCode *key, void *value)
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
Main function that will be run.
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
static void do_accept(void *cls)
Accept new incoming connections.
static int header_iterator(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
static struct PluginListEntry * plugins_tail
Plugin list tail.
static struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
static int echo_origin
Echo request Origin in CORS.
static struct AcceptedRequest * req_list_tail
AcceptedRequest list tail.
static void load_plugin(void *cls, const char *libname, void *lib_ret)
Callback for plugin load.
int main(int argc, char *const *argv)
The main function for gnunet-rest-service.
static char * allow_credentials
Allowed Credentials (CORS)
static void schedule_httpd()
Schedule MHD.
static struct MHD_Response * failure_response
Response we return on failures.
static in_addr_t address
The address to bind to.
static void mhd_connection_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_ConnectionNotificationCode cnc)
Function called when MHD connection is opened or closed.
static struct PluginListEntry * plugins_head
Plugin list head.
static void cleanup_handle(struct MhdConnectionHandle *handle)
static struct GNUNET_SCHEDULER_Task * ltask6
The listen task ID for IPv6.
static struct GNUNET_SCHEDULER_Task * ltask4
The listen task ID for IPv4.
static struct GNUNET_NETWORK_Handle * bind_v4()
Create an IPv4 listen socket bound to our port.
GNUnet service REST plugin header.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
enum GNUNET_GenericReturnValue GNUNET_DISK_file_test(const char *fil)
Check that fil corresponds to a filename (of a file that exists and that is not a directory).
enum GNUNET_GenericReturnValue GNUNET_DISK_fn_write(const char *fn, const void *buf, size_t buf_size, enum GNUNET_DISK_AccessPermissions mode)
Write a buffer to a file atomically.
ssize_t GNUNET_DISK_fn_read(const char *fn, void *result, size_t len)
Read the contents of a binary file into a buffer.
@ GNUNET_DISK_PERM_USER_READ
Owner can read.
@ GNUNET_DISK_PERM_USER_WRITE
Owner can write.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_MultiHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
void * GNUNET_CONTAINER_multihashmap_get(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Given a key find a value in the map matching the key.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
#define GNUNET_log(kind,...)
@ GNUNET_SCHEDULER_PRIORITY_DEFAULT
Run with the default priority (normal P2P operations).
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_free_nz(ptr)
Wrapper around free.
struct sockaddr * GNUNET_NETWORK_get_addr(const struct GNUNET_NETWORK_Handle *desc)
Return the sockaddr for this network handle.
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
void GNUNET_NETWORK_fdset_copy_native(struct GNUNET_NETWORK_FDSet *to, const fd_set *from, int nfds)
Copy a native fd set into the GNUnet representation.
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_accept(const struct GNUNET_NETWORK_Handle *desc, struct sockaddr *address, socklen_t *address_len)
Accept a new connection on a socket.
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
void GNUNET_NETWORK_socket_free_memory_only_(struct GNUNET_NETWORK_Handle *desc)
Only free memory of a socket, keep the file descriptor untouched.
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_default(void)
Return default project data used by 'libgnunetutil' for GNUnet.
void * GNUNET_PLUGIN_unload(const char *library_name, void *arg)
Unload plugin (runs the "done" callback and returns whatever "done" returned).
void GNUNET_PLUGIN_load_all_in_context(const struct GNUNET_OS_ProjectData *ctx, const char *basename, void *arg, GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls)
Load all compatible plugins with the given base name while inside the given context (i....
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_select(enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when any of the specified file descriptor set...
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
enum GNUNET_GenericReturnValue GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
enum GNUNET_GenericReturnValue GNUNET_STRINGS_utf8_tolower(const char *input, char *output)
Convert the utf-8 input string to lower case.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
@ MHD_HTTP_NOT_FOUND
Not Found [RFC7231, Section 6.5.4].
static unsigned int size
Size of the "table".
struct AcceptedRequest * prev
DLL.
int socket_with_mhd
State.
struct MhdConnectionHandle * con_handle
Connection.
struct GNUNET_NETWORK_Handle * sock
Socket.
struct AcceptedRequest * next
DLL.
Definition of a command line option.
collection of IO descriptors
struct returned by the initialization function of the plugin
enum GNUNET_GenericReturnValue(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
struct GNUNET_CONTAINER_MultiHashMap * header_param_map
Map of headers.
const char * data
The POST data.
const char * url
The url as string.
const char * method
The HTTP method as MHD value (see microhttpd.h)
struct GNUNET_CONTAINER_MultiHashMap * url_param_map
Map of url parameters.
size_t data_size
The POST data size.
Entry in list of pending tasks.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
struct GNUNET_REST_RequestHandle * data_handle
struct MHD_PostProcessor * pp
struct MHD_Response * response
struct MHD_Connection * con
struct PluginListEntry * prev
struct GNUNET_REST_Plugin * plugin
The plugin.
char * libname
libname (to cleanup)
struct PluginListEntry * next