static void respond_with_error (const gchar *original_path, const gchar *path, GIOStream *io_stream, GHashTable *headers, guint status, const gchar *message) { CockpitWebResponse *response; response = cockpit_web_response_new (io_stream, original_path, path, NULL, headers); cockpit_web_response_error (response, status, NULL, "%s", message); g_object_unref (response); }
static void respond_with_error (const gchar *original_path, const gchar *path, GIOStream *io_stream, gboolean for_tls_proxy, GHashTable *headers, guint status, const gchar *message) { CockpitWebResponse *response; response = cockpit_web_response_new (io_stream, original_path, path, NULL, headers, for_tls_proxy ? COCKPIT_WEB_RESPONSE_FOR_TLS_PROXY : COCKPIT_WEB_RESPONSE_NONE); cockpit_web_response_error (response, status, NULL, "%s", message); g_object_unref (response); }
static void process_delayed_reply (CockpitRequest *request, const gchar *path, GHashTable *headers) { CockpitWebResponse *response; const gchar *host; const gchar *body; GBytes *bytes; gsize length; gchar *url; g_assert (request->delayed_reply > 299); response = cockpit_web_response_new (request->io, NULL, NULL, headers); g_signal_connect_data (response, "done", G_CALLBACK (on_web_response_done), g_object_ref (request->web_server), (GClosureNotify)g_object_unref, 0); if (request->delayed_reply == 301) { body = "<html><head><title>Moved</title></head>" "<body>Please use TLS</body></html>"; host = g_hash_table_lookup (headers, "Host"); url = g_strdup_printf ("https://%s%s", host != NULL ? host : "", path); length = strlen (body); cockpit_web_response_headers (response, 301, "Moved Permanently", length, "Content-Type", "text/html", "Location", url, NULL); g_free (url); bytes = g_bytes_new_static (body, length); if (cockpit_web_response_queue (response, bytes)) cockpit_web_response_complete (response); g_bytes_unref (bytes); } else { cockpit_web_response_error (response, request->delayed_reply, NULL, NULL); } g_object_unref (response); }
static gboolean cockpit_web_server_default_handle_stream (CockpitWebServer *self, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input, guint in_length) { CockpitWebResponse *response; gboolean claimed = FALSE; GQuark detail; gchar *pos; gchar bak; /* Yes, we happen to know that we can modify this string safely. */ pos = strchr (path, '?'); if (pos != NULL) { *pos = '\0'; pos++; } /* TODO: Correct HTTP version for response */ response = cockpit_web_response_new (io_stream, path, pos, headers); g_signal_connect_data (response, "done", G_CALLBACK (on_web_response_done), g_object_ref (self), (GClosureNotify)g_object_unref, 0); /* * If the path has more than one component, then we search * for handlers registered under the detail like this: * * /component/ * * Otherwise we search for handlers registered under detail * of the entire path: * * /component */ /* Temporarily null terminate string after first component */ pos = NULL; if (path[0] != '\0') { pos = strchr (path + 1, '/'); if (pos != NULL) { pos++; bak = *pos; *pos = '\0'; } } detail = g_quark_try_string (path); if (pos != NULL) *pos = bak; /* See if we have any takers... */ g_signal_emit (self, sig_handle_resource, detail, path, headers, response, &claimed); /* TODO: Here is where we would plug keep-alive into respnse */ g_object_unref (response); return claimed; }
gboolean cockpit_handler_external (CockpitWebServer *server, const gchar *original_path, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input, CockpitHandlerData *ws) { CockpitWebResponse *response = NULL; CockpitWebService *service = NULL; const gchar *segment = NULL; JsonObject *open = NULL; const gchar *query = NULL; CockpitCreds *creds; const gchar *expected; const gchar *upgrade; guchar *decoded; GBytes *bytes; gsize length; gsize seglen; /* The path must start with /cockpit+xxx/channel/csrftoken? or similar */ if (path && path[0]) segment = strchr (path + 1, '/'); if (!segment) return FALSE; if (!g_str_has_prefix (segment, "/channel/")) return FALSE; segment += 9; /* Make sure we are authenticated, otherwise 404 */ service = cockpit_auth_check_cookie (ws->auth, path, headers); if (!service) return FALSE; creds = cockpit_web_service_get_creds (service); g_return_val_if_fail (creds != NULL, FALSE); expected = cockpit_creds_get_csrf_token (creds); g_return_val_if_fail (expected != NULL, FALSE); /* The end of the token */ query = strchr (segment, '?'); if (query) { seglen = query - segment; query += 1; } else { seglen = strlen (segment); query = ""; } /* No such path is valid */ if (strlen (expected) != seglen || memcmp (expected, segment, seglen) != 0) { g_message ("invalid csrf token"); return FALSE; } decoded = g_base64_decode (query, &length); if (decoded) { bytes = g_bytes_new_take (decoded, length); if (!cockpit_transport_parse_command (bytes, NULL, NULL, &open)) { open = NULL; g_message ("invalid external channel query"); } g_bytes_unref (bytes); } if (!open) { response = cockpit_web_response_new (io_stream, original_path, path, NULL, headers); cockpit_web_response_error (response, 400, NULL, NULL); g_object_unref (response); } else { upgrade = g_hash_table_lookup (headers, "Upgrade"); if (upgrade && g_ascii_strcasecmp (upgrade, "websocket") == 0) { cockpit_channel_socket_open (service, open, original_path, path, io_stream, headers, input); } else { response = cockpit_web_response_new (io_stream, original_path, path, NULL, headers); cockpit_channel_response_open (service, headers, response, open); g_object_unref (response); } json_object_unref (open); } g_object_unref (service); return TRUE; }
static gboolean on_handle_stream_external (CockpitWebServer *server, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input, gpointer user_data) { CockpitWebResponse *response; gboolean handled = FALSE; const gchar *upgrade; CockpitCreds *creds; const gchar *expected; const gchar *query; const gchar *segment; JsonObject *open = NULL; GBytes *bytes; guchar *decoded; gsize length; gsize seglen; if (g_str_has_prefix (path, "/cockpit/echosocket")) { const gchar *protocols[] = { "cockpit1", NULL }; const gchar *origins[2] = { NULL, NULL }; WebSocketConnection *ws = NULL; gchar *url; url = g_strdup_printf ("ws://localhost:%u%s", server_port, path); origins[0] = g_strdup_printf ("http://localhost:%u", server_port); ws = web_socket_server_new_for_stream (url, (const gchar **)origins, protocols, io_stream, headers, input); g_signal_connect (ws, "message", G_CALLBACK (on_echo_socket_message), NULL); g_signal_connect (ws, "close", G_CALLBACK (on_echo_socket_close), NULL); return TRUE; } if (!g_str_has_prefix (path, "/cockpit/channel/")) return FALSE; /* Remove /cockpit/channel/ part */ segment = path + 17; if (service) { creds = cockpit_web_service_get_creds (service); g_return_val_if_fail (creds != NULL, FALSE); expected = cockpit_creds_get_csrf_token (creds); g_return_val_if_fail (expected != NULL, FALSE); /* The end of the token */ query = strchr (segment, '?'); if (!query) query = segment + strlen (segment); /* No such path is valid */ seglen = query - segment; if (strlen(expected) == seglen && memcmp (expected, segment, seglen) == 0) { decoded = g_base64_decode (query, &length); if (decoded) { bytes = g_bytes_new_take (decoded, length); if (!cockpit_transport_parse_command (bytes, NULL, NULL, &open)) { open = NULL; g_message ("invalid external channel query"); } g_bytes_unref (bytes); } } if (open) { upgrade = g_hash_table_lookup (headers, "Upgrade"); if (upgrade && g_ascii_strcasecmp (upgrade, "websocket") == 0) { cockpit_channel_socket_open (service, open, path, io_stream, headers, input); handled = TRUE; } else { response = cockpit_web_response_new (io_stream, path, NULL, headers); cockpit_channel_response_open (service, headers, response, open); g_object_unref (response); handled = TRUE; } json_object_unref (open); } } return handled; }