Ejemplo n.º 1
0
/**
 * g_mapped_file_get_bytes:
 * @file: a #GMappedFile
 *
 * Creates a new #GBytes which references the data mapped from @file.
 * The mapped contents of the file must not be modified after creating this
 * bytes object, because a #GBytes should be immutable.
 *
 * Returns: (transfer full): A newly allocated #GBytes referencing data
 *     from @file
 *
 * Since: 2.34
 **/
GBytes *
g_mapped_file_get_bytes (GMappedFile *file)
{
  g_return_val_if_fail (file != NULL, NULL);

  return g_bytes_new_with_free_func (file->contents,
				     file->length,
				     (GDestroyNotify) g_mapped_file_unref,
				     g_mapped_file_ref (file));
}
Ejemplo n.º 2
0
static void prv_soup_server_cb(SoupServer *server, SoupMessage *msg,
			       const char *path, GHashTable *query,
			       SoupClientContext *client, gpointer user_data)
{
	rsu_host_file_t *hf;
	rsu_host_server_t *hs = user_data;
	const gchar *file_name;
	SoupMessageHeaders *hdrs;

	if (msg->method != SOUP_METHOD_GET) {
		soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
		goto on_error;
	}

	hf = prv_host_server_find_file(hs, path, &file_name);

	if (!hf) {
		soup_message_set_status(msg, SOUP_STATUS_NOT_FOUND);
		goto on_error;
	}

	if (hf->mapped_file) {
		g_mapped_file_ref(hf->mapped_file);
		++hf->mapped_count;
	} else {
		hf->mapped_file = g_mapped_file_new(file_name, FALSE, NULL);

		if (!hf->mapped_file) {
			soup_message_set_status(msg, SOUP_STATUS_NOT_FOUND);
			goto on_error;
		}

		hf->mapped_count = 1;
	}

	g_signal_connect(msg, "finished",
			 G_CALLBACK(prv_soup_message_finished_cb), hf);

	g_object_get(msg, "response-headers", &hdrs, NULL);

	/* TODO: Need to add the relevant DLNA headers */

/*	soup_message_headers_append(hdrs, "contentFeatures.dlna.org",
				    "DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=01;"DLNA.ORG_FLAGS=00f00000000000000000000000000000");
	soup_message_headers_append(hdrs, "Connection", "close");
*/
	soup_message_set_status(msg, SOUP_STATUS_OK);
	soup_message_set_response(msg, hf->mime_type, SOUP_MEMORY_STATIC,
				  g_mapped_file_get_contents(hf->mapped_file),
				  g_mapped_file_get_length(hf->mapped_file));

on_error:

	return;
}
Ejemplo n.º 3
0
TestHttp*
test_http_new(
    GMappedFile* resp_file,
    const char* resp_content_type,
    int resp_status)
{
    TestHttp* http = g_new0(TestHttp, 1);
    http->ref_count = 1;
    if (resp_file) {
        http->resp_file = g_mapped_file_ref(resp_file);
        http->resp_content_type = g_strdup(resp_content_type);
    }
    http->resp_status = resp_status;
    http->server = g_object_new(SOUP_TYPE_SERVER, NULL);
    MMS_DEBUG("Listening on port %hu", soup_server_get_port(http->server));
    soup_server_add_handler(http->server, NULL, test_http_callback, http, NULL);
    soup_server_run_async(http->server);
    return http;
}
Ejemplo n.º 4
0
static void
do_get (OtTrivialHttpd    *self,
        SoupServer        *server,
        SoupMessage       *msg,
        const char        *path,
        SoupClientContext *context)
{
  char *slash;
  int ret;
  struct stat stbuf;

  httpd_log (self, "serving %s\n", path);

  if (opt_expected_cookies)
    {
      GSList *cookies = soup_cookies_from_request (msg);
      GSList *l;
      int i;

      for (i = 0 ; opt_expected_cookies[i] != NULL; i++)
        {
          gboolean found = FALSE;
          gchar *k = opt_expected_cookies[i];
          gchar *v = strchr (k, '=') + 1;

          for (l = cookies;  l != NULL ; l = g_slist_next (l))
            {
              SoupCookie *c = l->data;

              if (!strncmp (k, soup_cookie_get_name (c), v - k - 1) &&
                  !strcmp (v, soup_cookie_get_value (c)))
                {
                  found = TRUE;
                  break;
                }
            }

          if (!found)
            {
              httpd_log (self, "Expected cookie not found %s\n", k);
              soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
              soup_cookies_free (cookies);
              goto out;
            }
        }
      soup_cookies_free (cookies);
    }

  if (opt_expected_headers)
    {
      for (int i = 0 ; opt_expected_headers[i] != NULL; i++)
        {
          const gchar *kv = opt_expected_headers[i];
          const gchar *eq = strchr (kv, '=');

          g_assert (eq);

          {
            g_autofree char *k = g_strndup (kv, eq - kv);
            const gchar *expected_v = eq + 1;
            const gchar *found_v = soup_message_headers_get_one (msg->request_headers, k);

            if (!found_v)
              {
                httpd_log (self, "Expected header not found %s\n", k);
                soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
                goto out;
              }
            if (strcmp (found_v, expected_v) != 0)
              {
                httpd_log (self, "Expected header %s: %s but found %s\n", k, expected_v, found_v);
                soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
                goto out;
              }
          }
        }
    }

  if (strstr (path, "../") != NULL)
    {
      soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      goto out;
    }

  if (opt_random_500s_percentage > 0 &&
      emitted_random_500s_count < opt_random_500s_max &&
      g_random_int_range (0, 100) < opt_random_500s_percentage)
    {
      emitted_random_500s_count++;
      soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
      goto out;
    }

  while (path[0] == '/')
    path++;

  do
    ret = fstatat (self->root_dfd, path, &stbuf, 0);
  while (ret == -1 && errno == EINTR);
  if (ret == -1)
    {
      if (errno == EPERM)
        soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      else if (errno == ENOENT)
        soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
      else
        soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
      goto out;
    }

  if (!is_safe_to_access (&stbuf))
    {
      soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      goto out;
    }

  if (S_ISDIR (stbuf.st_mode))
    {
      slash = strrchr (path, '/');
      if (!slash || slash[1])
        {
          g_autofree char *redir_uri = NULL;

          redir_uri = g_strdup_printf ("%s/", soup_message_get_uri (msg)->path);
          soup_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY,
                                     redir_uri);
        }
      else
        {
          g_autofree char *index_realpath = g_strconcat (path, "/index.html", NULL);
          if (fstatat (self->root_dfd, index_realpath, &stbuf, 0) != -1)
            {
              g_autofree char *index_path = g_strconcat (path, "/index.html", NULL);
              do_get (self, server, msg, index_path, context);
            }
          else
            {
              GString *listing = get_directory_listing (self->root_dfd, path);
              soup_message_set_response (msg, "text/html",
                                         SOUP_MEMORY_TAKE,
                                         listing->str, listing->len);
              soup_message_set_status (msg, SOUP_STATUS_OK);
              g_string_free (listing, FALSE);
            }
        }
    }
  else 
    {
      if (!S_ISREG (stbuf.st_mode))
        {
          soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
          goto out;
        }
      
      if (msg->method == SOUP_METHOD_GET)
        {
          glnx_autofd int fd = -1;
          g_autoptr(GMappedFile) mapping = NULL;
          gsize buffer_length, file_size;
          SoupRange *ranges;
          int ranges_length;
          gboolean have_ranges;

          fd = openat (self->root_dfd, path, O_RDONLY | O_CLOEXEC);
          if (fd < 0)
            {
              soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
              goto out;
            }

          mapping = g_mapped_file_new_from_fd (fd, FALSE, NULL);
          if (!mapping)
            {
              soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
              goto out;
            }
          (void) close (fd); fd = -1;

          file_size = g_mapped_file_get_length (mapping);
          have_ranges = soup_message_headers_get_ranges(msg->request_headers, file_size, &ranges, &ranges_length);
          if (opt_force_ranges && !have_ranges && g_strrstr (path, "/objects") != NULL)
            {
              SoupSocket *sock;
              buffer_length = file_size/2;
              soup_message_headers_set_content_length (msg->response_headers, file_size);
              soup_message_headers_append (msg->response_headers,
                                           "Connection", "close");

              /* soup-message-io will wait for us to add
               * another chunk after the first, to fill out
               * the declared Content-Length. Instead, we
               * forcibly close the socket at that point.
               */
              sock = soup_client_context_get_socket (context);
              g_signal_connect (msg, "wrote-chunk", G_CALLBACK (close_socket), sock);
            }
          else
            buffer_length = file_size;

          if (have_ranges)
            {
              if (ranges_length > 0 && ranges[0].start >= file_size)
                {
                  soup_message_set_status (msg, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
                  soup_message_headers_free_ranges (msg->request_headers, ranges);
                  goto out;
                }
              soup_message_headers_free_ranges (msg->request_headers, ranges);
            }
          if (buffer_length > 0)
            {
              SoupBuffer *buffer;

              buffer = soup_buffer_new_with_owner (g_mapped_file_get_contents (mapping),
                                                   buffer_length,
                                                   g_mapped_file_ref (mapping),
                                                   (GDestroyNotify)g_mapped_file_unref);
              soup_message_body_append_buffer (msg->response_body, buffer);
              soup_buffer_free (buffer);
            }
        }
      else /* msg->method == SOUP_METHOD_HEAD */
        {
          g_autofree char *length = NULL;

          /* We could just use the same code for both GET and
           * HEAD (soup-message-server-io.c will fix things up).
           * But we'll optimize and avoid the extra I/O.
           */
          length = g_strdup_printf ("%lu", (gulong)stbuf.st_size);
          soup_message_headers_append (msg->response_headers,
                                       "Content-Length", length);
        }
      soup_message_set_status (msg, SOUP_STATUS_OK);
    }
 out:
  {
    guint status = 0;
    g_autofree gchar *reason = NULL;

    g_object_get (msg,
                  "status-code", &status,
                  "reason-phrase", &reason,
                  NULL);
    httpd_log (self, "  status: %s (%u)\n", reason, status);
  }
  return;
}
Ejemplo n.º 5
0
static void prv_soup_server_cb(SoupServer *server, SoupMessage *msg,
			       const char *path, GHashTable *query,
			       SoupClientContext *client, gpointer user_data)
{
	dlr_host_file_t *hf;
	dlr_host_server_t *hs = user_data;
	const gchar *file_name;
	const char *hdr;

	if ((msg->method != SOUP_METHOD_GET) &&
	    (msg->method != SOUP_METHOD_HEAD)) {
		soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
		goto on_error;
	}

	hf = prv_host_server_find_file(hs, path, &file_name);

	if (!hf) {
		soup_message_set_status(msg, SOUP_STATUS_NOT_FOUND);
		goto on_error;
	}

	hdr = soup_message_headers_get_one(msg->request_headers,
					   "getContentFeatures.dlna.org");

	if (hdr) {
		if (strcmp(hdr, "1") != 0) {
			soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
			goto on_error;
		}

		if ((hf->dlna_header) && strlen(hf->dlna_header) > 0)
			soup_message_headers_append(msg->response_headers,
						    "contentFeatures.dlna.org",
						    hf->dlna_header);
	}

	if (hf->mapped_file) {
		g_mapped_file_ref(hf->mapped_file);
		++hf->mapped_count;
	} else {
		hf->mapped_file = g_mapped_file_new(file_name,
						    FALSE,
						    NULL);

		if (!hf->mapped_file) {
			soup_message_set_status(msg,
						SOUP_STATUS_NOT_FOUND);
			goto on_error;
		}

		hf->mapped_count = 1;
	}

	if (msg->method == SOUP_METHOD_GET) {
		g_signal_connect(msg, "finished",
				 G_CALLBACK(prv_soup_message_finished_cb), hf);

		soup_message_set_response(
				msg, hf->mime_type,
				SOUP_MEMORY_STATIC,
				g_mapped_file_get_contents(hf->mapped_file),
				g_mapped_file_get_length(hf->mapped_file));
	} else {
		soup_message_headers_set_content_type(msg->response_headers,
						      hf->mime_type, NULL);

		soup_message_headers_set_content_length(
			msg->response_headers,
			g_mapped_file_get_length(hf->mapped_file));
	}

	soup_message_set_status(msg, SOUP_STATUS_OK);

on_error:

	return;
}
Ejemplo n.º 6
0
static void
do_get (OtTrivialHttpd    *self,
        SoupServer        *server,
        SoupMessage       *msg,
        const char        *path,
        SoupClientContext *context)
{
  char *slash;
  int ret;
  struct stat stbuf;
  g_autofree char *safepath = NULL;

  httpd_log (self, "serving %s\n", path);
  if (strstr (path, "../") != NULL)
    {
      soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      goto out;
    }

  if (opt_random_500s_percentage > 0 &&
      emitted_random_500s_count < opt_random_500s_max &&
      g_random_int_range (0, 100) < opt_random_500s_percentage)
    {
      emitted_random_500s_count++;
      soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
      goto out;
    }

  if (path[0] == '/')
    path++;

  safepath = g_build_filename (gs_file_get_path_cached (self->root), path, NULL);

  do
    ret = stat (safepath, &stbuf);
  while (ret == -1 && errno == EINTR);
  if (ret == -1)
    {
      if (errno == EPERM)
        soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      else if (errno == ENOENT)
        soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
      else
        soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
      goto out;
    }

  if (!is_safe_to_access (&stbuf))
    {
      soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
      goto out;
    }

  if (S_ISDIR (stbuf.st_mode))
    {
      slash = strrchr (safepath, '/');
      if (!slash || slash[1])
        {
          g_autofree char *redir_uri = NULL;

          redir_uri = g_strdup_printf ("%s/", soup_message_get_uri (msg)->path);
          soup_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY,
                                     redir_uri);
        }
      else
        {
          g_autofree char *index_realpath = g_strconcat (safepath, "/index.html", NULL);
          if (stat (index_realpath, &stbuf) != -1)
            {
              g_autofree char *index_path = g_strconcat (path, "/index.html", NULL);
              do_get (self, server, msg, index_path, context);
            }
          else
            {
              GString *listing = get_directory_listing (safepath);
              soup_message_set_response (msg, "text/html",
                                         SOUP_MEMORY_TAKE,
                                         listing->str, listing->len);
              soup_message_set_status (msg, SOUP_STATUS_OK);
              g_string_free (listing, FALSE);
            }
        }
    }
  else 
    {
      if (!S_ISREG (stbuf.st_mode))
        {
          soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
          goto out;
        }
      
      if (msg->method == SOUP_METHOD_GET)
        {
          g_autoptr(GMappedFile) mapping = NULL;
          gsize buffer_length, file_size;
          SoupRange *ranges;
          int ranges_length;
          gboolean have_ranges;

          mapping = g_mapped_file_new (safepath, FALSE, NULL);
          if (!mapping)
            {
              soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
              goto out;
            }

          file_size = g_mapped_file_get_length (mapping);
          have_ranges = soup_message_headers_get_ranges(msg->request_headers, file_size, &ranges, &ranges_length);
          if (opt_force_ranges && !have_ranges && g_strrstr (path, "/objects") != NULL)
            {
              SoupSocket *sock;
              buffer_length = file_size/2;
              soup_message_headers_set_content_length (msg->response_headers, file_size);
              soup_message_headers_append (msg->response_headers,
                                           "Connection", "close");

              /* soup-message-io will wait for us to add
               * another chunk after the first, to fill out
               * the declared Content-Length. Instead, we
               * forcibly close the socket at that point.
               */
              sock = soup_client_context_get_socket (context);
              g_signal_connect (msg, "wrote-chunk", G_CALLBACK (close_socket), sock);
            }
          else
            buffer_length = file_size;

          if (have_ranges)
            {
              if (ranges_length > 0 && ranges[0].start >= file_size)
                {
                  soup_message_set_status (msg, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
                  soup_message_headers_free_ranges (msg->request_headers, ranges);
                  goto out;
                }
              soup_message_headers_free_ranges (msg->request_headers, ranges);
            }
          if (buffer_length > 0)
            {
              SoupBuffer *buffer;

              buffer = soup_buffer_new_with_owner (g_mapped_file_get_contents (mapping),
                                                   buffer_length,
                                                   g_mapped_file_ref (mapping),
                                                   (GDestroyNotify)g_mapped_file_unref);
              soup_message_body_append_buffer (msg->response_body, buffer);
              soup_buffer_free (buffer);
            }
        }
      else /* msg->method == SOUP_METHOD_HEAD */
        {
          g_autofree char *length = NULL;

          /* We could just use the same code for both GET and
           * HEAD (soup-message-server-io.c will fix things up).
           * But we'll optimize and avoid the extra I/O.
           */
          length = g_strdup_printf ("%lu", (gulong)stbuf.st_size);
          soup_message_headers_append (msg->response_headers,
                                       "Content-Length", length);
        }
      soup_message_set_status (msg, SOUP_STATUS_OK);
    }
 out:
  {
    guint status = 0;
    g_autofree gchar *reason = NULL;

    g_object_get (msg,
                  "status-code", &status,
                  "reason-phrase", &reason,
                  NULL);
    httpd_log (self, "  status: %s (%u)\n", reason, status);
  }
  return;
}