Пример #1
0
static gboolean
relay_length (CockpitHttpStream *self,
              CockpitChannel *channel,
              GByteArray *buffer)
{
  GBytes *message = NULL;
  gsize block;

  g_assert (self->response_length >= 0);

  if (self->response_length == 0)
    {
      /* All done, yay */
      g_debug ("%s: received enough bytes", self->name);
      cockpit_channel_close (channel, NULL);
      g_assert (self->state == FINISHED);
    }
  else if (buffer->len == 0)
    {
      /* Not enough data? */
      return FALSE;
    }
  else
    {
      block = MIN (buffer->len, self->response_length);
      self->response_length -= block;

      message = cockpit_pipe_consume (buffer, 0, block, 0);
      relay_data (channel, message);
      g_bytes_unref (message);
    }

  return TRUE;
}
Пример #2
0
static void
on_pipe_read (CockpitPipe *pipe,
              GByteArray *input,
              gboolean end_of_data,
              gpointer user_data)
{
  CockpitPipeTransport *self = COCKPIT_PIPE_TRANSPORT (user_data);
  GBytes *message;
  GBytes *payload;
  gchar *channel;
  guint32 size;

  for (;;)
    {
      if (input->len < sizeof (size))
        {
          if (!end_of_data)
            g_debug ("%s: want more data", self->name);
          break;
        }

      memcpy (&size, input->data, sizeof (size));
      size = GUINT32_FROM_BE (size);
      if (input->len < size + sizeof (size))
        {
          g_debug ("%s: want more data", self->name);
          break;
        }

      message = cockpit_pipe_consume (input, sizeof (size), size);
      payload = cockpit_transport_parse_frame (message, &channel);
      if (payload)
        {
          g_debug ("%s: received a %d byte payload", self->name, (int)size);
          cockpit_transport_emit_recv ((CockpitTransport *)self, channel, payload);
          g_bytes_unref (payload);
          g_free (channel);
        }
      g_bytes_unref (message);
    }

  if (end_of_data)
    {
      /* Received a partial message */
      if (input->len > 0)
        {
          g_warning ("%s: received truncated %d byte frame", self->name, input->len);
          cockpit_pipe_close (pipe, "internal-error");
        }
    }
}
Пример #3
0
static void
drain_buffer (CockpitSshTransport *self)
{
  GBytes *message;
  GBytes *payload;
  gchar *channel;
  guint32 size;

  for (;;)
    {
      if (self->buffer->len < sizeof (size))
        {
          if (!self->received_eof)
            g_debug ("%s: want len have %d", self->logname, (int)self->buffer->len);
          break;
        }

      memcpy (&size, self->buffer->data, sizeof (size));
      size = GUINT32_FROM_BE (size);
      if (self->buffer->len < size + sizeof (size))
        {
          g_debug ("%s: want %d have %d", self->logname,
                   (int)(size + sizeof (size)), (int)self->buffer->len);
          break;
        }

      message = cockpit_pipe_consume (self->buffer, sizeof (size), size, 0);
      payload = cockpit_transport_parse_frame (message, &channel);
      if (payload)
        {
          g_debug ("%s: received a %d byte payload", self->logname, (int)g_bytes_get_size (payload));
          cockpit_transport_emit_recv ((CockpitTransport *)self, channel, payload);
          g_bytes_unref (payload);
          g_free (channel);
        }
      g_bytes_unref (message);
    }

  if (self->received_eof)
    {
      /* Received a partial message */
      if (self->buffer->len > 0)
        {
          g_warning ("%s: received truncated %d byte frame", self->logname, (int)self->buffer->len);
          close_immediately (self, "internal-error");
        }
    }
}
Пример #4
0
static gboolean
relay_all (CockpitHttpStream *self,
           CockpitChannel *channel,
           GByteArray *buffer)
{
  GBytes *message;

  if (buffer->len == 0)
    {
      /* Not enough data? */
      return FALSE;
    }

  message = cockpit_pipe_consume (buffer, 0, buffer->len, 0);
  relay_data (channel, message);
  g_bytes_unref (message);

  return TRUE;
}
Пример #5
0
static void
on_pipe_read (CockpitPipe *pipe,
              GByteArray *input,
              gboolean end_of_data,
              gpointer user_data)
{
  CockpitInteractTransport *self = COCKPIT_INTERACT_TRANSPORT (user_data);
  GBytes *message;
  GBytes *payload;
  gchar *channel;
  guint8 *pos;
  guint32 size;

  for (;;)
    {
      pos = NULL;
      if (input->len > 0)
        pos = (guint8 *)g_strstr_len ((gchar *)input->data, input->len, self->delimiter);
      if (!pos)
        {
          if (!end_of_data)
            g_debug ("%s: want more data", self->name);
          break;
        }

      size = pos - input->data;
      message = cockpit_pipe_consume (input, 0, size, self->delimiter_len);

      payload = cockpit_transport_parse_frame (message, &channel);
      if (payload)
        {
          g_debug ("%s: received a %d byte payload", self->name, (int)size);
          cockpit_transport_emit_recv ((CockpitTransport *)self, channel, payload);
          g_bytes_unref (payload);
          g_free (channel);
        }
      g_bytes_unref (message);
    }
}
Пример #6
0
/**
 * cockpit_transport_read_from_pipe:
 *
 * Meant to be used in a "read" handler for a #CockpitPipe
 * Closed is pointer to a boolean value that may be updated
 * during the read and parse loop.
 */
void
cockpit_transport_read_from_pipe (CockpitTransport *self,
                                  const gchar *logname,
                                  CockpitPipe *pipe,
                                  gboolean *closed,
                                  GByteArray *input,
                                  gboolean end_of_data)
{
  GBytes *message;
  GBytes *payload;
  gchar *channel;
  guint32 i, size;
  gchar *data;

  /* This may be updated during the loop. */
  g_assert (closed != NULL);
  g_object_ref (self);

  while (!*closed)
    {
      size = 0;
      data = (gchar *)input->data;
      for (i = 0; i < input->len; i++)
        {
          /* Check invalid characters, prevent integer overflow, limit max length */
          if (i > 7 || data[i] < '0' || data[i] > '9')
            break;
          size *= 10;
          size += data[i] - '0';
        }

      if (i == input->len)
        {
          if (!end_of_data)
            g_debug ("%s: want more data", logname);
          break;
        }

      if (data[i] != '\n')
        {
          g_warning ("%s: incorrect protocol: received invalid length prefix", logname);
          cockpit_pipe_close (pipe, "protocol-error");
          break;
        }

      if (input->len < i + 1 + size)
        {
          g_debug ("%s: want more data 2", logname);
          break;
        }

      message = cockpit_pipe_consume (input, i + 1, size, 0);
      payload = cockpit_transport_parse_frame (message, &channel);
      if (payload)
        {
          g_debug ("%s: received a %d byte payload", logname, (int)size);
          cockpit_transport_emit_recv (self, channel, payload);
          g_bytes_unref (payload);
          g_free (channel);
        }
      g_bytes_unref (message);
    }

  if (end_of_data)
    {
      /* Received a partial message */
      if (input->len > 0)
        {
          g_debug ("%s: received truncated %d byte frame", logname, input->len);
          cockpit_pipe_close (pipe, "disconnected");
        }
    }

  g_object_unref (self);
}
Пример #7
0
static void
on_pipe_read (CockpitPipe *pipe,
              GByteArray *input,
              gboolean end_of_data,
              gpointer user_data)
{
  CockpitPipeTransport *self = COCKPIT_PIPE_TRANSPORT (user_data);
  GBytes *message;
  GBytes *payload;
  gchar *channel;
  guint32 i, size;
  gchar *data;

  g_object_ref (self);

  for (;;)
    {
      size = 0;
      data = (gchar *)input->data;
      for (i = 0; i < input->len; i++)
        {
          /* Check invalid characters, prevent integer overflow, limit max length */
          if (i > 7 || data[i] < '0' || data[i] > '9')
            break;
          size *= 10;
          size += data[i] - '0';
        }

      if (i == input->len)
        {
          if (!end_of_data)
            g_debug ("%s: want more data", self->name);
          break;
        }

      if (data[i] != '\n')
        {
          g_warning ("%s: incorrect protocol: received invalid length prefix", self->name);
          cockpit_pipe_close (pipe, "protocol-error");
          break;
        }

      if (input->len < i + 1 + size)
        {
          g_debug ("%s: want more data 2", self->name);
          break;
        }

      message = cockpit_pipe_consume (input, i + 1, size, 0);
      payload = cockpit_transport_parse_frame (message, &channel);
      if (payload)
        {
          g_debug ("%s: received a %d byte payload", self->name, (int)size);
          cockpit_transport_emit_recv ((CockpitTransport *)self, channel, payload);
          g_bytes_unref (payload);
          g_free (channel);
        }
      g_bytes_unref (message);
    }

  if (end_of_data)
    {
      /* Received a partial message */
      if (input->len > 0)
        {
          g_debug ("%s: received truncated %d byte frame", self->name, input->len);
          cockpit_pipe_close (pipe, "disconnected");
        }
    }

  g_object_unref (self);
}
Пример #8
0
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;
}