Exemple #1
0
static void
postal_http_router (SoupServer        *server,
                    SoupMessage       *message,
                    const gchar       *path,
                    GHashTable        *query,
                    SoupClientContext *client,
                    gpointer           user_data)
{
   PostalHttpPrivate *priv;
   PostalHttp *http = user_data;

   ENTRY;

   g_assert(SOUP_IS_SERVER(server));
   g_assert(SOUP_IS_MESSAGE(message));
   g_assert(path);
   g_assert(client);
   g_assert(POSTAL_IS_HTTP(http));

   priv = http->priv;

   g_object_set_data_full(G_OBJECT(message),
                          "http",
                          g_object_ref(http),
                          g_object_unref);

   if (!url_router_route(priv->router, server, message, path, query, client)) {
      soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
   }

   EXIT;
}
/**
 * soup_server_get_port:
 * @server: a #SoupServer
 *
 * Gets the TCP port that @server is listening on. This is most useful
 * when you did not request a specific port (or explicitly requested
 * %SOUP_ADDRESS_ANY_PORT).
 *
 * Return value: the port @server is listening on.
 **/
guint
soup_server_get_port (SoupServer *server)
{
	g_return_val_if_fail (SOUP_IS_SERVER (server), 0);

	return SOUP_SERVER_GET_PRIVATE (server)->port;
}
/**
 * soup_server_add_handler:
 * @server: a #SoupServer
 * @path: the toplevel path for the handler
 * @callback: callback to invoke for requests under @path
 * @user_data: data for @callback
 * @destroy: destroy notifier to free @user_data
 *
 * Adds a handler to @server for requests under @path. See the
 * documentation for #SoupServerCallback for information about
 * how callbacks should behave.
 *
 * If @path is %NULL or "/", then this will be the default handler for
 * all requests that don't have a more specific handler. Note though
 * that if you want to handle requests to the special "*" URI, you
 * must explicitly register a handler for "*"; the default handler
 * will not be used for that case.
 **/
void
soup_server_add_handler (SoupServer            *server,
			 const char            *path,
			 SoupServerCallback     callback,
			 gpointer               user_data,
			 GDestroyNotify         destroy)
{
	SoupServerPrivate *priv;
	SoupServerHandler *hand;

	g_return_if_fail (SOUP_IS_SERVER (server));
	g_return_if_fail (callback != NULL);
	priv = SOUP_SERVER_GET_PRIVATE (server);

	/* "" was never documented as meaning the same this as "/",
	 * but it effectively was. We have to special case it now or
	 * otherwise it would match "*" too.
	 */
	if (path && (!*path || !strcmp (path, "/")))
		path = NULL;

	hand = g_slice_new0 (SoupServerHandler);
	hand->path       = g_strdup (path);
	hand->callback   = callback;
	hand->destroy    = destroy;
	hand->user_data  = user_data;

	soup_server_remove_handler (server, path);
	if (path)
		soup_path_map_add (priv->handlers, path, hand);
	else
		priv->default_handler = hand;
}
/**
 * soup_server_unpause_message:
 * @server: a #SoupServer
 * @msg: a #SoupMessage associated with @server.
 *
 * Resumes I/O on @msg. Use this to resume after calling
 * soup_server_pause_message(), or after adding a new chunk to a
 * chunked response.
 *
 * I/O won't actually resume until you return to the main loop.
 **/
void
soup_server_unpause_message (SoupServer *server,
			     SoupMessage *msg)
{
	g_return_if_fail (SOUP_IS_SERVER (server));
	g_return_if_fail (SOUP_IS_MESSAGE (msg));

	soup_message_io_unpause (msg);
}
/**
 * soup_server_is_https:
 * @server: a #SoupServer
 *
 * Checks whether @server is running plain http or https.
 *
 * In order for a server to run https, you must set the
 * %SOUP_SERVER_SSL_CERT_FILE and %SOUP_SERVER_SSL_KEY_FILE properties
 * to provide it with an SSL certificate to use.
 *
 * Return value: %TRUE if @server is serving https.
 **/
gboolean
soup_server_is_https (SoupServer *server)
{
	SoupServerPrivate *priv;

	g_return_val_if_fail (SOUP_IS_SERVER (server), 0);
	priv = SOUP_SERVER_GET_PRIVATE (server);

	return (priv->ssl_cert_file && priv->ssl_key_file);
}
/**
 * soup_server_get_listener:
 * @server: a #SoupServer
 *
 * Gets @server's listening socket. You should treat this as
 * read-only; writing to it or modifiying it may cause @server to
 * malfunction.
 *
 * Return value: the listening socket.
 **/
SoupSocket *
soup_server_get_listener (SoupServer *server)
{
	SoupServerPrivate *priv;

	g_return_val_if_fail (SOUP_IS_SERVER (server), NULL);
	priv = SOUP_SERVER_GET_PRIVATE (server);

	return priv->listen_sock;
}
/**
 * soup_server_get_async_context:
 * @server: a #SoupServer
 *
 * Gets @server's async_context. This does not add a ref to the
 * context, so you will need to ref it yourself if you want it to
 * outlive its server.
 *
 * Return value: @server's #GMainContext, which may be %NULL
 **/
GMainContext *
soup_server_get_async_context (SoupServer *server)
{
	SoupServerPrivate *priv;

	g_return_val_if_fail (SOUP_IS_SERVER (server), NULL);
	priv = SOUP_SERVER_GET_PRIVATE (server);

	return priv->async_context;
}
/**
 * soup_server_remove_auth_domain:
 * @server: a #SoupServer
 * @auth_domain: a #SoupAuthDomain
 *
 * Removes @auth_domain from @server.
 **/
void
soup_server_remove_auth_domain (SoupServer *server, SoupAuthDomain *auth_domain)
{
	SoupServerPrivate *priv;

	g_return_if_fail (SOUP_IS_SERVER (server));
	priv = SOUP_SERVER_GET_PRIVATE (server);

	priv->auth_domains = g_slist_remove (priv->auth_domains, auth_domain);
	g_object_unref (auth_domain);
}
/**
 * soup_server_quit:
 * @server: a #SoupServer
 *
 * Stops processing for @server. Call this to clean up after
 * soup_server_run_async(), or to terminate a call to soup_server_run().
 *
 * @server is still in a working state after this call; you can start
 * and stop a server as many times as you want.
 **/
void
soup_server_quit (SoupServer *server)
{
	SoupServerPrivate *priv;

	g_return_if_fail (SOUP_IS_SERVER (server));
	priv = SOUP_SERVER_GET_PRIVATE (server);

	g_signal_handlers_disconnect_by_func (priv->listen_sock,
					      G_CALLBACK (new_connection),
					      server);
	if (priv->loop)
		g_main_loop_quit (priv->loop);
}
Exemple #10
0
void
web_setup (WebFixture *fix, gconstpointer data)
{
	if (!PORT)
		PORT = 52853;
	fix->server = soup_server_new (SOUP_SERVER_PORT, PORT, NULL);
	while (!SOUP_IS_SERVER (fix->server)) {
		PORT++;
		fix->server = soup_server_new (SOUP_SERVER_PORT, PORT, NULL);
	}

	soup_server_add_handler (fix->server, "/feeds/", feed_server, NULL, NULL);
	soup_server_add_handler (fix->server, "/video/", video_server, NULL, NULL);
	soup_server_add_handler (fix->server, "/redirect/", redirect_server, NULL, NULL);
	soup_server_run_async (fix->server);
}
Exemple #11
0
/**
 * soup_server_run:
 * @server: a #SoupServer
 *
 * Starts @server, causing it to listen for and process incoming
 * connections. Unlike soup_server_run_async(), this creates a
 * #GMainLoop and runs it, and it will not return until someone calls
 * soup_server_quit() to stop the server.
 **/
void
soup_server_run (SoupServer *server)
{
	SoupServerPrivate *priv;

	g_return_if_fail (SOUP_IS_SERVER (server));
	priv = SOUP_SERVER_GET_PRIVATE (server);

	if (!priv->loop) {
		priv->loop = g_main_loop_new (priv->async_context, TRUE);
		soup_server_run_async (server);
	}

	if (priv->loop)
		g_main_loop_run (priv->loop);
}
Exemple #12
0
static SoupServerHandler *
soup_server_get_handler (SoupServer *server, const char *path)
{
	SoupServerPrivate *priv;
	SoupServerHandler *hand;

	g_return_val_if_fail (SOUP_IS_SERVER (server), NULL);
	priv = SOUP_SERVER_GET_PRIVATE (server);

	if (path) {
		hand = soup_path_map_lookup (priv->handlers, path);
		if (hand)
			return hand;
		if (!strcmp (path, "*"))
			return NULL;
	}
	return priv->default_handler;
}
Exemple #13
0
static void
postal_http_handle_v1_users_user_devices (UrlRouter         *router,
                                          SoupServer        *server,
                                          SoupMessage       *message,
                                          const gchar       *path,
                                          GHashTable        *params,
                                          GHashTable        *query,
                                          SoupClientContext *client,
                                          gpointer           user_data)
{
   const gchar *user;
   PostalHttp *http = user_data;

   ENTRY;

   g_assert(router);
   g_assert(SOUP_IS_SERVER(server));
   g_assert(SOUP_IS_MESSAGE(message));
   g_assert(path);
   g_assert(params);
   g_assert(g_hash_table_contains(params, "user"));
   g_assert(client);
   g_assert(POSTAL_IS_HTTP(http));

   user = g_hash_table_lookup(params, "user");
   soup_server_pause_message(server, message);

   if (message->method == SOUP_METHOD_GET) {
      postal_service_find_devices(http->priv->service,
                                  user,
                                  get_int_param(query, "offset"),
                                  get_int_param(query, "limit"),
                                  NULL, /* TODO */
                                  devices_get_cb,
                                  g_object_ref(message));
      EXIT;
   }

   soup_message_set_status(message, SOUP_STATUS_METHOD_NOT_ALLOWED);
   soup_server_unpause_message(server, message);

   EXIT;
}
Exemple #14
0
/**
 * soup_server_run_async:
 * @server: a #SoupServer
 *
 * Starts @server, causing it to listen for and process incoming
 * connections.
 *
 * The server actually runs in @server's #GMainContext. It will not
 * actually perform any processing unless the appropriate main loop is
 * running. In the simple case where you did not set the server's
 * %SOUP_SERVER_ASYNC_CONTEXT property, this means the server will run
 * whenever the glib main loop is running.
 **/
void
soup_server_run_async (SoupServer *server)
{
	SoupServerPrivate *priv;

	g_return_if_fail (SOUP_IS_SERVER (server));
	priv = SOUP_SERVER_GET_PRIVATE (server);

	if (!priv->listen_sock) {
		if (priv->loop) {
			g_main_loop_unref (priv->loop);
			priv->loop = NULL;
		}
		return;
	}

	g_signal_connect (priv->listen_sock, "new_connection",
			  G_CALLBACK (new_connection), server);

	return;

}
Exemple #15
0
/**
 * soup_server_remove_handler:
 * @server: a #SoupServer
 * @path: the toplevel path for the handler
 *
 * Removes the handler registered at @path.
 **/
void
soup_server_remove_handler (SoupServer *server, const char *path)
{
	SoupServerPrivate *priv;
	SoupServerHandler *hand;

	g_return_if_fail (SOUP_IS_SERVER (server));
	priv = SOUP_SERVER_GET_PRIVATE (server);

	if (!path || !*path || !strcmp (path, "/")) {
		if (priv->default_handler) {
			unregister_handler (priv->default_handler);
			free_handler (priv->default_handler);
			priv->default_handler = NULL;
		}
		return;
	}

	hand = soup_path_map_lookup (priv->handlers, path);
	if (hand && !strcmp (path, hand->path)) {
		unregister_handler (hand);
		soup_path_map_remove (priv->handlers, path);
	}
}
Exemple #16
0
static void
postal_http_handle_v1_users_user_badge (UrlRouter         *router,
                                        SoupServer        *server,
                                        SoupMessage       *message,
                                        const gchar       *path,
                                        GHashTable        *params,
                                        GHashTable        *query,
                                        SoupClientContext *client,
                                        gpointer           user_data)
{
   const gchar *user;
   PostalHttp *http = user_data;
   JsonNode *node = NULL;
   GError *error = NULL;
   guint badge;

   ENTRY;

   g_assert(router);
   g_assert(SOUP_IS_SERVER(server));
   g_assert(SOUP_IS_MESSAGE(message));
   g_assert(path);
   g_assert(params);
   g_assert(g_hash_table_contains(params, "user"));
   g_assert(client);
   g_assert(POSTAL_IS_HTTP(http));

   user = g_hash_table_lookup(params, "user");

   if (message->method == SOUP_METHOD_PUT) {
      if (!(node = postal_http_parse_body(message, &error)) ||
          !JSON_NODE_HOLDS_VALUE(node)) {
         if (!error) {
            error = g_error_new(JSON_PARSER_ERROR,
                                JSON_PARSER_ERROR_UNKNOWN,
                                _("JSON must contain integer."));
         }
         postal_http_reply_error(http, message, error);
         GOTO(cleanup);
      }
      badge = json_node_get_int(node);
      g_object_set_data(G_OBJECT(message), "http", http);
      postal_service_set_user_badge(http->priv->service,
                                    user,
                                    badge,
                                    NULL,
                                    postal_http_set_user_badge_cb,
                                    g_object_ref(message));
      soup_server_pause_message(server, message);
      EXIT;
   }

   soup_message_set_status(message, SOUP_STATUS_METHOD_NOT_ALLOWED);

cleanup:
   g_clear_error(&error);
   if (node) {
      json_node_free(node);
   }

   EXIT;
}
Exemple #17
0
static void
postal_http_handle_v1_notify (UrlRouter         *router,
                              SoupServer        *server,
                              SoupMessage       *message,
                              const gchar       *path,
                              GHashTable        *params,
                              GHashTable        *query,
                              SoupClientContext *client,
                              gpointer           user_data)
{
   PostalNotification *notif;
   const gchar *collapse_key = NULL;
   const gchar *str;
   PostalHttp *http = user_data;
   JsonObject *aps;
   JsonObject *c2dm;
   JsonObject *gcm;
   JsonObject *object;
   JsonArray *devices;
   JsonArray *users;
   GPtrArray *devices_ptr;
   GPtrArray *users_ptr;
   JsonNode *node;
   GError *error = NULL;
   guint count;
   guint i;

   g_assert(SOUP_IS_SERVER(server));
   g_assert(SOUP_IS_MESSAGE(message));
   g_assert(path);
   g_assert(client);
   g_assert(POSTAL_IS_HTTP(http));

   if (message->method != SOUP_METHOD_POST) {
      soup_message_set_status(message, SOUP_STATUS_METHOD_NOT_ALLOWED);
      return;
   }

   soup_server_pause_message(server, message);

   if (!(node = postal_http_parse_body(message, &error))) {
      postal_http_reply_error(http, message, error);
      g_error_free(error);
      return;
   }

   if (!JSON_NODE_HOLDS_OBJECT(node) ||
       !(object = json_node_get_object(node)) ||
       !json_object_has_member(object, "aps") ||
       !(node = json_object_get_member(object, "aps")) ||
       !JSON_NODE_HOLDS_OBJECT(node) ||
       !(aps = json_object_get_object_member(object, "aps")) ||
       !json_object_has_member(object, "c2dm") ||
       !(node = json_object_get_member(object, "c2dm")) ||
       !JSON_NODE_HOLDS_OBJECT(node) ||
       !(c2dm = json_object_get_object_member(object, "c2dm")) ||
       !json_object_has_member(object, "gcm") ||
       !(node = json_object_get_member(object, "gcm")) ||
       !JSON_NODE_HOLDS_OBJECT(node) ||
       !(gcm = json_object_get_object_member(object, "gcm")) ||
       !json_object_has_member(object, "users") ||
       !(node = json_object_get_member(object, "users")) ||
       !JSON_NODE_HOLDS_ARRAY(node) ||
       !(users = json_object_get_array_member(object, "users")) ||
       !json_object_has_member(object, "devices") ||
       !(node = json_object_get_member(object, "devices")) ||
       !JSON_NODE_HOLDS_ARRAY(node) ||
       !(devices = json_object_get_array_member(object, "devices"))) {
      error = g_error_new(postal_json_error_quark(), 0,
                          "Missing or invalid fields in JSON payload.");
      postal_http_reply_error(http, message, error);
      json_node_free(node);
      g_error_free(error);
      return;
   }

   if (json_object_has_member(object, "collapse_key") &&
       (node = json_object_get_member(object, "collapse_key")) &&
       JSON_NODE_HOLDS_VALUE(node)) {
      collapse_key = json_node_get_string(node);
   }

   notif = g_object_new(POSTAL_TYPE_NOTIFICATION,
                        "aps", aps,
                        "c2dm", c2dm,
                        "collapse-key", collapse_key,
                        "gcm", gcm,
                        NULL);

   count = json_array_get_length(users);
   users_ptr = g_ptr_array_sized_new(count);
   for (i = 0; i < count; i++) {
      node = json_array_get_element(users, i);
      if (json_node_get_value_type(node) == G_TYPE_STRING) {
         str = json_node_get_string(node);
         g_ptr_array_add(users_ptr, (gchar *)str);
      }
   }
   g_ptr_array_add(users_ptr, NULL);

   count = json_array_get_length(devices);
   devices_ptr = g_ptr_array_sized_new(count);
   g_ptr_array_set_free_func(devices_ptr, g_free);
   for (i = 0; i < count; i++) {
      node = json_array_get_element(devices, i);
      if (json_node_get_value_type(node) == G_TYPE_STRING) {
         str = json_node_get_string(node);
         g_ptr_array_add(devices_ptr, g_strdup(str));
      }
   }
   g_ptr_array_add(devices_ptr, NULL);

   postal_service_notify(http->priv->service,
                         notif,
                         (gchar **)users_ptr->pdata,
                         (gchar **)devices_ptr->pdata,
                         NULL, /* TODO: Cancellable/Timeout? */
                         postal_http_notify_cb,
                         g_object_ref(message));

   g_ptr_array_unref(devices_ptr);
   g_ptr_array_unref(users_ptr);
   json_node_free(node);
   g_object_unref(notif);
}
Exemple #18
0
gboolean
url_router_route (UrlRouter         *router,
                  SoupServer        *server,
                  SoupMessage       *message,
                  const gchar       *path,
                  GHashTable        *query,
                  SoupClientContext *client)
{
   UrlNodeData *data;
   const gchar *cur;
   const gchar *end;
   GHashTable *params = NULL;
   gboolean ret = FALSE;
   GNode *node = (GNode *)router;
   gchar *part;

   g_return_val_if_fail(router, FALSE);
   g_return_val_if_fail(SOUP_IS_SERVER(server), FALSE);
   g_return_val_if_fail(SOUP_IS_MESSAGE(message), FALSE);
   g_return_val_if_fail(path, FALSE);
   g_return_val_if_fail(client, FALSE);

   cur = path;
   if (*path != '/') {
      return FALSE;
   }
   cur++;

   while (node && *cur) {
      if (!(node = node->children)) {
         break;
      }

      end = cur;
      while (*end && *end != '/') end++;

      for (; node; node = node->next) {
         data = node->data;
         if (data->catchall) {
            if (!params) {
               params = g_hash_table_new_full(g_str_hash, g_str_equal,
                                              NULL, g_free);
            }
            part = g_strndup(cur, end - cur);
            g_hash_table_insert(params, (gchar *)data->key + 1, part);
            break;
         } else if (url_node_data_match(data, cur, end - cur)) {
            break;
         }
      }

      cur = end;
      if (*cur == '/') cur++;
   }

   if (node && (data = node->data) && data->handler) {
      data->handler(router,
                    server,
                    message,
                    path,
                    params,
                    query,
                    client,
                    data->handler_data);
      ret = TRUE;
   }

   if (params) {
      g_hash_table_unref(params);
   }

   return ret;
}
Exemple #19
0
static void
postal_http_handle_v1_users_user_devices_device (UrlRouter         *router,
                                                 SoupServer        *server,
                                                 SoupMessage       *message,
                                                 const gchar       *path,
                                                 GHashTable        *params,
                                                 GHashTable        *query,
                                                 SoupClientContext *client,
                                                 gpointer           user_data)
{
   PostalDevice *pdev;
   const gchar *user;
   const gchar *device;
   PostalHttp *http = user_data;
   GError *error = NULL;
   JsonNode *node;

   ENTRY;

   g_assert(router);
   g_assert(SOUP_IS_SERVER(server));
   g_assert(SOUP_IS_MESSAGE(message));
   g_assert(path);
   g_assert(params);
   g_assert(g_hash_table_contains(params, "device"));
   g_assert(g_hash_table_contains(params, "user"));
   g_assert(client);
   g_assert(POSTAL_IS_HTTP(http));

   device = g_hash_table_lookup(params, "device");
   user = g_hash_table_lookup(params, "user");

   if (message->method == SOUP_METHOD_GET) {
      postal_service_find_device(http->priv->service,
                                 user,
                                 device,
                                 NULL, /* TODO */
                                 postal_http_find_device_cb,
                                 g_object_ref(message));
      soup_server_pause_message(server, message);
      EXIT;
   } else if (message->method == SOUP_METHOD_DELETE) {
      pdev = g_object_new(POSTAL_TYPE_DEVICE,
                          "device-token", device,
                          "user", user,
                          NULL);
      postal_service_remove_device(http->priv->service,
                                   pdev,
                                   NULL, /* TODO */
                                   postal_http_remove_device_cb,
                                   g_object_ref(message));
      soup_server_pause_message(server, message);
      g_object_unref(pdev);
      EXIT;
   } else if (message->method == SOUP_METHOD_PUT) {
      if (!(node = postal_http_parse_body(message, &error))) {
         postal_http_reply_error(http, message, error);
         soup_server_unpause_message(server, message);
         g_error_free(error);
         EXIT;
      }
      pdev = postal_device_new();
      if (!postal_device_load_from_json(pdev, node, &error)) {
         postal_http_reply_error(http, message, error);
         soup_server_unpause_message(server, message);
         json_node_free(node);
         g_error_free(error);
         g_object_unref(pdev);
         EXIT;
      }
      postal_device_set_device_token(pdev, device);
      postal_device_set_user(pdev, user);
      json_node_free(node);
      g_object_set_data_full(G_OBJECT(message),
                             "device",
                             g_object_ref(pdev),
                             g_object_unref);
      postal_service_add_device(http->priv->service,
                                pdev,
                                NULL, /* TODO */
                                postal_http_add_device_cb,
                                g_object_ref(message));
      soup_server_pause_message(server, message);
      g_object_unref(pdev);
      EXIT;
   } else {
      soup_message_set_status(message, SOUP_STATUS_METHOD_NOT_ALLOWED);
      EXIT;
   }

   g_assert_not_reached();
}