static void cockpit_web_server_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CockpitWebServer *server = COCKPIT_WEB_SERVER (object); switch (prop_id) { case PROP_PORT: server->port = g_value_get_int (value); break; case PROP_CERTIFICATE: server->certificate = g_value_dup_object (value); break; case PROP_DOCUMENT_ROOTS: server->document_roots = filter_document_roots (g_value_get_boxed (value)); break; case PROP_SSL_EXCEPTION_PREFIX: g_string_assign (server->ssl_exception_prefix, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void cockpit_web_server_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CockpitWebServer *server = COCKPIT_WEB_SERVER (object); switch (prop_id) { case PROP_PORT: g_value_set_int (value, cockpit_web_server_get_port (server)); break; case PROP_CERTIFICATE: g_value_set_object (value, server->certificate); break; case PROP_DOCUMENT_ROOTS: g_value_set_boxed (value, cockpit_web_server_get_document_roots (server)); break; case PROP_SSL_EXCEPTION_PREFIX: g_value_set_string (value, server->ssl_exception_prefix->str); case PROP_SOCKET_ACTIVATED: g_value_set_boolean (value, server->socket_activated); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void on_local_ready (GObject *object, GAsyncResult *result, gpointer data) { cockpit_web_server_start (COCKPIT_WEB_SERVER (data)); g_object_unref (data); }
static void cockpit_web_server_dispose (GObject *object) { CockpitWebServer *self = COCKPIT_WEB_SERVER (object); g_hash_table_remove_all (self->requests); G_OBJECT_CLASS (cockpit_web_server_parent_class)->dispose (object); }
static void cockpit_web_server_constructed (GObject *object) { CockpitWebServer *server = COCKPIT_WEB_SERVER (object); static gchar *default_roots[] = { ".", NULL }; G_OBJECT_CLASS (cockpit_web_server_parent_class)->constructed (object); if (server->document_roots == NULL) server->document_roots = g_strdupv (default_roots); }
static gboolean on_incoming (GSocketService *service, GSocketConnection *connection, GObject *source_object, gpointer user_data) { CockpitWebServer *self = COCKPIT_WEB_SERVER (user_data); cockpit_request_start (self, G_IO_STREAM (connection), TRUE); /* handled */ return TRUE; }
static void cockpit_web_server_finalize (GObject *object) { CockpitWebServer *server = COCKPIT_WEB_SERVER (object); g_clear_object (&server->certificate); g_strfreev (server->document_roots); g_hash_table_destroy (server->requests); if (server->main_context) g_main_context_unref (server->main_context); g_string_free (server->ssl_exception_prefix, TRUE); g_clear_object (&server->socket_service); G_OBJECT_CLASS (cockpit_web_server_parent_class)->finalize (object); }
CockpitWebServer * cockpit_web_server_new (gint port, GTlsCertificate *certificate, const gchar **document_roots, GCancellable *cancellable, GError **error) { GInitable *initable; initable = g_initable_new (COCKPIT_TYPE_WEB_SERVER, cancellable, error, "port", port, "certificate", certificate, "document-roots", document_roots, NULL); if (initable != NULL) return COCKPIT_WEB_SERVER (initable); else return NULL; }
static gboolean cockpit_web_server_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { CockpitWebServer *server = COCKPIT_WEB_SERVER (initable); gboolean ret = FALSE; gboolean failed = FALSE; int n, fd; server->socket_service = g_socket_service_new (); n = sd_listen_fds (0); if (n > 0) { /* We got file descriptors passed in, use those. */ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { GSocket *s = NULL; gboolean b; int type; socklen_t l = sizeof (type); /* * HACK: Workaround g_error() happy code in GSocket * https://bugzilla.gnome.org/show_bug.cgi?id=746339 */ if (getsockopt (fd, SOL_SOCKET, SO_TYPE, &type, &l) < 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "invalid socket passed via systemd activation: %d: %s", fd, g_strerror (errno)); goto out; } s = g_socket_new_from_fd (fd, error); if (s == NULL) { g_prefix_error (error, "Failed to acquire passed socket %i: ", fd); goto out; } b = cockpit_web_server_add_socket (server, s, error); g_object_unref (s); if (!b) { g_prefix_error (error, "Failed to add listener for socket %i: ", fd); goto out; } } server->socket_activated = TRUE; } else { /* No fds passed in, let's listen on our own. */ if (server->port == 0) { server->port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (server->socket_service), NULL, error); failed = (server->port == 0); } else if (server->port > 0) { failed = !g_socket_listener_add_inet_port (G_SOCKET_LISTENER (server->socket_service), server->port, NULL, error); } if (failed) { g_prefix_error (error, "Failed to bind to port %d: ", server->port); goto out; } } g_signal_connect (server->socket_service, "incoming", G_CALLBACK (on_incoming), server); ret = TRUE; out: return ret; }
static void cockpit_web_server_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CockpitWebServer *server = COCKPIT_WEB_SERVER (object); GString *str; const gchar *address = NULL; switch (prop_id) { case PROP_PORT: server->port = g_value_get_int (value); break; case PROP_ADDRESS: address = g_value_get_string (value); if (address) { server->address = g_inet_address_new_from_string (address); if (!server->address) g_warning ("Couldn't parse IP address from: %s", address); } break; case PROP_CERTIFICATE: server->certificate = g_value_dup_object (value); break; case PROP_DOCUMENT_ROOTS: server->document_roots = cockpit_web_server_resolve_roots (g_value_get_boxed (value)); break; case PROP_SSL_EXCEPTION_PREFIX: g_string_assign (server->ssl_exception_prefix, g_value_get_string (value)); break; case PROP_URL_ROOT: str = g_string_new (g_value_get_string (value)); while (str->str[0] == '/') g_string_erase (str, 0, 1); if (str->len) { while (str->str[str->len - 1] == '/') g_string_truncate (str, str->len - 1); } if (str->len) g_string_printf (server->url_root, "/%s", str->str); else g_string_assign (server->url_root, str->str); g_string_free (str, TRUE); break; case PROP_REDIRECT_TLS: server->redirect_tls = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean cockpit_web_server_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { CockpitWebServer *server = COCKPIT_WEB_SERVER (initable); gboolean ret = FALSE; gboolean failed; int n, fd; server->socket_service = g_socket_service_new (); n = sd_listen_fds (0); if (n > 0) { /* We got file descriptors passed in, use those. */ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { GSocket *s = NULL; gboolean b; s = g_socket_new_from_fd (fd, error); if (s == NULL) { g_prefix_error (error, "Failed to acquire passed socket %i: ", fd); goto out; } b = g_socket_listener_add_socket (G_SOCKET_LISTENER (server->socket_service), s, NULL, error); g_object_unref (s); if (!b) { g_prefix_error (error, "Failed to add listener for socket %i: ", fd); goto out; } } server->socket_activated = TRUE; } else { /* No fds passed in, let's listen on our own. */ if (server->port == 0) { server->port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (server->socket_service), NULL, error); failed = (server->port == 0); } else { failed = !g_socket_listener_add_inet_port (G_SOCKET_LISTENER (server->socket_service), server->port, NULL, error); } if (failed) { g_prefix_error (error, "Failed to bind to port %d: ", server->port); goto out; } } g_signal_connect (server->socket_service, "incoming", G_CALLBACK (on_incoming), server); ret = TRUE; out: return ret; }