void cockpit_channel_socket_open (CockpitWebService *service, JsonObject *open, const gchar *original_path, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input_buffer, gboolean for_tls_proxy) { CockpitChannelSocket *self = NULL; WebSocketDataType data_type; CockpitTransport *transport; gchar **protocols = NULL; gchar *id = NULL; if (!cockpit_web_service_parse_external (open, NULL, NULL, NULL, &protocols) || !cockpit_web_service_parse_binary (open, &data_type)) { respond_with_error (original_path, path, io_stream, for_tls_proxy, headers, 400, "Bad channel request"); goto out; } transport = cockpit_web_service_get_transport (service); if (!transport) { respond_with_error (original_path, path, io_stream, for_tls_proxy, headers, 502, "Failed to open channel transport"); goto out; } json_object_set_boolean_member (open, "flow-control", TRUE); id = cockpit_web_service_unique_channel (service); self = g_object_new (COCKPIT_TYPE_CHANNEL_SOCKET, "transport", transport, "options", open, "id", id, NULL); self->data_type = data_type; self->socket = cockpit_web_service_create_socket ((const gchar **)protocols, original_path, io_stream, headers, input_buffer, for_tls_proxy); self->socket_open = g_signal_connect (self->socket, "open", G_CALLBACK (on_socket_open), self); self->socket_message = g_signal_connect (self->socket, "message", G_CALLBACK (on_socket_message), self); self->socket_close = g_signal_connect (self->socket, "close", G_CALLBACK (on_socket_close), self); /* Unref when the channel closes */ g_signal_connect_after (self, "closed", G_CALLBACK (g_object_unref), NULL); /* Tell the channel to throttle based on back pressure from socket */ cockpit_flow_throttle (COCKPIT_FLOW (self), COCKPIT_FLOW (self->socket)); /* Tell the socket peer's output to throttle based on back pressure */ cockpit_flow_throttle (COCKPIT_FLOW (self->socket), COCKPIT_FLOW (self)); out: g_free (id); g_free (protocols); }
void cockpit_channel_response_open (CockpitWebService *service, GHashTable *in_headers, CockpitWebResponse *response, JsonObject *open) { CockpitTransport *transport; WebSocketDataType data_type; GHashTable *headers; const gchar *content_type; const gchar *content_disposition; /* Parse the external */ if (!cockpit_web_service_parse_external (open, &content_type, &content_disposition, NULL)) { cockpit_web_response_error (response, 400, NULL, "Bad channel request"); return; } transport = cockpit_web_service_ensure_transport (service, open); if (!transport) { cockpit_web_response_error (response, 502, NULL, "Failed to open channel transport"); return; } headers = cockpit_web_server_new_table (); if (content_disposition) g_hash_table_insert (headers, g_strdup ("Content-Disposition"), g_strdup (content_disposition)); if (!json_object_has_member (open, "binary")) json_object_set_string_member (open, "binary", "raw"); if (!content_type) { if (!cockpit_web_service_parse_binary (open, &data_type)) g_return_if_reached (); if (data_type == WEB_SOCKET_DATA_TEXT) content_type = "text/plain"; else content_type = "application/octet-stream"; } g_hash_table_insert (headers, g_strdup ("Content-Type"), g_strdup (content_type)); /* We shouldn't need to send this part further */ json_object_remove_member (open, "external"); cockpit_channel_response_create (service, response, transport, NULL, headers, open); g_hash_table_unref (headers); }
void cockpit_channel_socket_open (CockpitWebService *service, JsonObject *open, const gchar *original_path, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input_buffer) { CockpitChannelSocket *chock = NULL; WebSocketDataType data_type; CockpitTransport *transport; gchar **protocols = NULL; if (!cockpit_web_service_parse_external (open, NULL, NULL, &protocols) || !cockpit_web_service_parse_binary (open, &data_type)) { respond_with_error (original_path, path, io_stream, headers, 400, "Bad channel request"); goto out; } transport = cockpit_web_service_ensure_transport (service, open); if (!transport) { respond_with_error (original_path, path, io_stream, headers, 502, "Failed to open channel transport"); goto out; } chock = g_new0 (CockpitChannelSocket, 1); chock->channel = cockpit_web_service_unique_channel (service); chock->open = json_object_ref (open); chock->data_type = data_type; json_object_set_string_member (open, "command", "open"); json_object_set_string_member (open, "channel", chock->channel); chock->socket = cockpit_web_service_create_socket ((const gchar **)protocols, original_path, io_stream, headers, input_buffer); chock->socket_open = g_signal_connect (chock->socket, "open", G_CALLBACK (on_socket_open), chock); chock->socket_message = g_signal_connect (chock->socket, "message", G_CALLBACK (on_socket_message), chock); chock->socket_close = g_signal_connect (chock->socket, "close", G_CALLBACK (on_socket_close), chock); chock->transport = g_object_ref (transport); chock->transport_recv = g_signal_connect (chock->transport, "recv", G_CALLBACK (on_transport_recv), chock); chock->transport_control = g_signal_connect (chock->transport, "control", G_CALLBACK (on_transport_control), chock); chock->transport_closed = g_signal_connect (chock->transport, "closed", G_CALLBACK (on_transport_closed), chock); out: g_free (protocols); }