static void on_helper_read (CockpitPipe *pipe, GByteArray *buffer, gboolean eof, gpointer user_data) { ReauthorizeCaller *caller = user_data; JsonObject *object; GBytes *bytes; guint8 *lf; lf = memchr (buffer->data, '\n', buffer->len); if (!lf) return; /* Null terminate the challenge */ *lf = 0; g_debug ("got challenge from helper, will send to cockpit-ws: %s", (gchar *)buffer->data); /* send an authorize packet here */ object = json_object_new (); json_object_set_string_member (object, "command", "authorize"); json_object_set_string_member (object, "cookie", caller->cookie); json_object_set_string_member (object, "challenge", (gchar *)buffer->data); bytes = cockpit_json_write_bytes (object); json_object_unref (object); /* Consume from buffer, including null termination */ cockpit_pipe_skip (buffer, lf - buffer->data); cockpit_transport_send (caller->self->transport, NULL, bytes); g_bytes_unref (bytes); }
static gboolean relay_chunked (CockpitHttpStream *self, CockpitChannel *channel, GByteArray *buffer) { GBytes *message; const gchar *data; const gchar *pos; guint64 size; gsize length; gsize beg; gchar *end; data = (const gchar *)buffer->data; length = buffer->len; pos = memchr (data, '\r', length); if (pos == NULL) return FALSE; /* want more data */ beg = (pos + 2) - data; if (length < beg) { /* have to have a least the ending chars */ return FALSE; /* want more data */ } size = g_ascii_strtoull (data, &end, 16); if (pos[1] != '\n' || end != pos) { cockpit_channel_fail (channel, "protocol-error", "%s: received invalid HTTP chunk", self->name); } else if (size > G_MAXSSIZE) { cockpit_channel_fail (channel, "protocol-error", "%s: received extremely large HTTP chunk", self->name); } else if (length < beg + size + 2) { return FALSE; /* want more data */ } else if (data[beg + size] != '\r' || data[beg + size + 1] != '\n') { cockpit_channel_fail (channel, "protocol-error", "%s: received invalid HTTP chunk data", self->name); } else if (size == 0) { /* All done, yay */ g_debug ("%s: received last chunk", self->name); cockpit_pipe_skip (buffer, beg + 2); cockpit_channel_close (channel, NULL); g_assert (self->state == FINISHED); } else { message = cockpit_pipe_consume (buffer, beg, size, 2); relay_data (channel, message); g_bytes_unref (message); return TRUE; } return TRUE; }
static gboolean relay_headers (CockpitHttpStream *self, CockpitChannel *channel, GByteArray *buffer) { GHashTable *headers = NULL; gchar *version = NULL; gchar *reason = NULL; JsonObject *object; const gchar *data; JsonObject *heads; GHashTableIter iter; GBytes *message; gpointer key; gpointer value; guint status; gsize length; gssize offset; gssize offset2; data = (const gchar *)buffer->data; length = buffer->len; offset = web_socket_util_parse_status_line (data, length, &version, &status, &reason); if (offset == 0) return FALSE; /* want more data */ if (offset < 0) { cockpit_channel_fail (channel, "protocol-error", "%s: received response with bad HTTP status line", self->name); goto out; } offset2 = web_socket_util_parse_headers (data + offset, length - offset, &headers); if (offset2 == 0) return FALSE; /* want more data */ if (offset2 < 0) { cockpit_channel_fail (channel, "protocol-error", "%s: received response with bad HTTP headers", self->name); goto out; } g_debug ("%s: response: %u %s", self->name, status, reason); g_hash_table_iter_init (&iter, headers); while (g_hash_table_iter_next (&iter, &key, &value)) g_debug ("%s: header: %s %s", self->name, (gchar *)key, (gchar *)value); if (!parse_transfer_encoding (self, channel, headers) || !parse_content_length (self, channel, status, headers) || !parse_keep_alive (self, channel, version, headers)) goto out; cockpit_pipe_skip (buffer, offset + offset2); if (!self->binary) { g_hash_table_remove (headers, "Content-Length"); g_hash_table_remove (headers, "Range"); } g_hash_table_remove (headers, "Connection"); g_hash_table_remove (headers, "Transfer-Encoding"); /* Now serialize all the rest of this into JSON */ object = json_object_new (); json_object_set_int_member (object, "status", status); json_object_set_string_member (object, "reason", reason); heads = json_object_new(); g_hash_table_iter_init (&iter, headers); while (g_hash_table_iter_next (&iter, &key, &value)) json_object_set_string_member (heads, key, value); json_object_set_object_member (object, "headers", heads); if (self->headers_inline) { message = cockpit_json_write_bytes (object); cockpit_channel_send (channel, message, TRUE); g_bytes_unref (message); } else { cockpit_channel_control (channel, "response", object); } json_object_unref (object); out: if (headers) g_hash_table_unref (headers); g_free (version); g_free (reason); return TRUE; }