gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-sync] branch master updated: implement GET logic


From: gnunet
Subject: [taler-sync] branch master updated: implement GET logic
Date: Fri, 15 Nov 2019 09:39:33 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository sync.

The following commit(s) were added to refs/heads/master by this push:
     new 9badf80  implement GET logic
9badf80 is described below

commit 9badf80eb4228a9c009839a4856710127efe8601
Author: Christian Grothoff <address@hidden>
AuthorDate: Fri Nov 15 09:39:31 2019 +0100

    implement GET logic
---
 src/include/sync_database_plugin.h  |  19 +++-
 src/include/sync_service.h          |   2 +-
 src/sync/sync-httpd.c               |  27 +++---
 src/sync/sync-httpd_backup.c        | 170 ++++++++++++++++++++++++++++++++++--
 src/sync/sync-httpd_backup.h        |  10 +--
 src/syncdb/plugin_syncdb_postgres.c | 108 +++++++++++++++++++++--
 6 files changed, 306 insertions(+), 30 deletions(-)

diff --git a/src/include/sync_database_plugin.h 
b/src/include/sync_database_plugin.h
index cdc65e9..d5759ee 100644
--- a/src/include/sync_database_plugin.h
+++ b/src/include/sync_database_plugin.h
@@ -38,7 +38,7 @@ enum SYNC_DB_QueryStatus
   SYNC_DB_OLD_BACKUP_MISSMATCH = -4,
 
   /**
-   * Account is unpaid.
+   * Account is unpaid / does not exist.
    */
   SYNC_DB_PAYMENT_REQUIRED = -3,
 
@@ -153,12 +153,28 @@ struct SYNC_DatabasePlugin
                       size_t backup_size,
                       const void *backup);
 
+
+  /**
+   * Lookup an account and associated backup meta data.
+   *
+   * @param cls closure
+   * @param account_pub account to store @a backup under
+   * @param backup_hash[OUT] set to hash of @a backup
+   * @return transaction status
+   */
+  enum SYNC_DB_QueryStatus
+  (*lookup_account_TR)(void *cls,
+                       const struct SYNC_AccountPublicKeyP *account_pub,
+                       struct GNUNET_HashCode *backup_hash);
+
+
   /**
    * Obtain backup.
    *
    * @param cls closure
    * @param account_pub account to store @a backup under
    * @param account_sig[OUT] set to signature affirming storage request
+   * @param prev_hash[OUT] set to hash of the previous @a backup (all zeros if 
none)
    * @param backup_hash[OUT] set to hash of @a backup
    * @param backup_size[OUT] set to number of bytes in @a backup
    * @param backup[OUT] set to raw data to backup, caller MUST FREE
@@ -167,6 +183,7 @@ struct SYNC_DatabasePlugin
   (*lookup_backup_TR)(void *cls,
                       const struct SYNC_AccountPublicKeyP *account_pub,
                       struct SYNC_AccountSignatureP *account_sig,
+                      struct GNUNET_HashCode *prev_hash,
                       struct GNUNET_HashCode *backup_hash,
                       size_t *backup_size,
                       void **backup);
diff --git a/src/include/sync_service.h b/src/include/sync_service.h
index e99d0c3..20bbe67 100644
--- a/src/include/sync_service.h
+++ b/src/include/sync_service.h
@@ -46,7 +46,7 @@ struct SYNC_AccountPublicKeyP
   /**
    * We use EdDSA.
    */
-  struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
+  struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
 };
 
 
diff --git a/src/sync/sync-httpd.c b/src/sync/sync-httpd.c
index d7f6eb5..98a2b24 100644
--- a/src/sync/sync-httpd.c
+++ b/src/sync/sync-httpd.c
@@ -175,7 +175,10 @@ url_handler (void *cls,
   struct TM_HandlerContext *hc;
   struct GNUNET_AsyncScopeId aid;
   const char *correlation_id = NULL;
+  struct SYNC_AccountPublicKeyP account_pub;
 
+  (void) cls;
+  (void) version;
   hc = *con_cls;
 
   if (NULL == hc)
@@ -197,7 +200,6 @@ url_handler (void *cls,
   {
     aid = hc->async_scope_id;
   }
-
   GNUNET_SCHEDULER_begin_async_scope (&aid);
 
   if (NULL != correlation_id)
@@ -211,22 +213,25 @@ url_handler (void *cls,
                 "Handling request (%s) for URL '%s'\n",
                 method,
                 url);
-  if (0 == strncmp (url,
-                    "/backup/",
-                    strlen ("/backup/")))
+
+  if (GNUNET_OK ==
+      GNUNET_CRYPTO_eddsa_public_key_from_string (url,
+                                                  strlen (url),
+                                                  &account_pub.eddsa_pub))
   {
-    // return handle_policy (...);
-    if (0 == strcmp (method, MHD_HTTP_METHOD_GET))
+    if (0 == strcasecmp (method,
+                         MHD_HTTP_METHOD_GET))
     {
       return sync_handler_backup_get (connection,
-                                      url,
+                                      &account_pub,
                                       con_cls);
     }
-    if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
+    if (0 == strcasecmp (method,
+                         MHD_HTTP_METHOD_POST))
     {
       return sync_handler_backup_post (connection,
                                        con_cls,
-                                       url,
+                                       &account_pub,
                                        upload_data,
                                        upload_data_size);
     }
@@ -238,8 +243,8 @@ url_handler (void *cls,
     if ( (0 == strcmp (url,
                        rh->url)) &&
          ( (NULL == rh->method) ||
-           (0 == strcmp (method,
-                         rh->method)) ) )
+           (0 == strcasecmp (method,
+                             rh->method)) ) )
     {
       int ret;
 
diff --git a/src/sync/sync-httpd_backup.c b/src/sync/sync-httpd_backup.c
index 86ba955..61d9151 100644
--- a/src/sync/sync-httpd_backup.c
+++ b/src/sync/sync-httpd_backup.c
@@ -21,26 +21,182 @@
 #include "platform.h"
 #include "sync-httpd.h"
 #include <gnunet/gnunet_util_lib.h>
+#include "sync-httpd_backup.h"
+#include "sync-httpd_responses.h"
 
 /**
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param account public key of the account the request is for
+ * @param[in,out] con_cls the connection's closure (can be updated)
  * @return MHD result code
  */
 int
 sync_handler_backup_get (struct MHD_Connection *connection,
-                         const char *url,
+                         const struct SYNC_AccountPublicKeyP *account,
                          void **con_cls)
 {
-  return MHD_NO;
+  struct SYNC_AccountSignatureP account_sig;
+  struct GNUNET_HashCode backup_hash;
+  struct GNUNET_HashCode prev_hash;
+  size_t backup_size;
+  void *backup;
+  enum SYNC_DB_QueryStatus qs;
+  struct MHD_Response *resp;
+  const char *inm;
+  struct GNUNET_HashCode inm_h;
+  int ret;
+
+  inm = MHD_lookup_connection_value (connection,
+                                     MHD_HEADER_KIND,
+                                     MHD_HTTP_HEADER_IF_NONE_MATCH);
+  qs = db->lookup_account_TR (db->cls,
+                              account,
+                              &backup_hash);
+  switch (qs)
+  {
+  case SYNC_DB_OLD_BACKUP_MISSMATCH:
+    GNUNET_break (0);
+    return SH_RESPONSE_reply_internal_error (connection,
+                                             
TALER_EC_INTERNAL_INVARIANT_FAILURE,
+                                             "unexpected return status (backup 
missmatch)");
+  case SYNC_DB_PAYMENT_REQUIRED:
+    return SH_RESPONSE_reply_not_found (connection,
+                                        TALER_EC_SYNC_ACCOUNT_UNKNOWN,
+                                        "account");
+  case SYNC_DB_HARD_ERROR:
+    GNUNET_break (0);
+    return SH_RESPONSE_reply_internal_error (connection,
+                                             TALER_EC_SYNC_DB_FETCH_ERROR,
+                                             "hard database failure");
+  case SYNC_DB_SOFT_ERROR:
+    GNUNET_break (0);
+    return SH_RESPONSE_reply_internal_error (connection,
+                                             TALER_EC_SYNC_DB_FETCH_ERROR,
+                                             "soft database failure");
+  case SYNC_DB_NO_RESULTS:
+    resp = MHD_create_response_from_buffer (0,
+                                            NULL,
+                                            MHD_RESPMEM_PERSISTENT);
+    ret = MHD_queue_response (connection,
+                              MHD_HTTP_NO_CONTENT,
+                              resp);
+    MHD_destroy_response (resp);
+    return ret;
+  case SYNC_DB_ONE_RESULT:
+    if (NULL != inm)
+    {
+      if (GNUNET_OK !=
+          GNUNET_STRINGS_string_to_data (inm,
+                                         strlen (inm),
+                                         &inm_h,
+                                         sizeof (inm_h)))
+      {
+        GNUNET_break_op (0);
+        return SH_RESPONSE_reply_bad_request (connection,
+                                              TALER_EC_SYNC_BAD_ETAG,
+                                              "Etag is not a base32-encoded 
SHA-512 hash");
+      }
+      if (0 == GNUNET_memcmp (&inm_h,
+                              &backup_hash))
+      {
+        resp = MHD_create_response_from_buffer (0,
+                                                NULL,
+                                                MHD_RESPMEM_PERSISTENT);
+        ret = MHD_queue_response (connection,
+                                  MHD_HTTP_NOT_MODIFIED,
+                                  resp);
+        MHD_destroy_response (resp);
+        return ret;
+      }
+    }
+    /* We have a result, should fetch and return it! */
+    break;
+  }
+
+  qs = db->lookup_backup_TR (db->cls,
+                             account,
+                             &account_sig,
+                             &prev_hash,
+                             &backup_hash,
+                             &backup_size,
+                             &backup);
+  switch (qs)
+  {
+  case SYNC_DB_OLD_BACKUP_MISSMATCH:
+    GNUNET_break (0);
+    return SH_RESPONSE_reply_internal_error (connection,
+                                             
TALER_EC_INTERNAL_INVARIANT_FAILURE,
+                                             "unexpected return status (backup 
missmatch)");
+  case SYNC_DB_PAYMENT_REQUIRED:
+    GNUNET_break (0);
+    return SH_RESPONSE_reply_internal_error (connection,
+                                             
TALER_EC_INTERNAL_INVARIANT_FAILURE,
+                                             "unexpected return status 
(payment required)");
+  case SYNC_DB_HARD_ERROR:
+    GNUNET_break (0);
+    return SH_RESPONSE_reply_internal_error (connection,
+                                             TALER_EC_SYNC_DB_FETCH_ERROR,
+                                             "hard database failure");
+  case SYNC_DB_SOFT_ERROR:
+    GNUNET_break (0);
+    return SH_RESPONSE_reply_internal_error (connection,
+                                             TALER_EC_SYNC_DB_FETCH_ERROR,
+                                             "soft database failure");
+  case SYNC_DB_NO_RESULTS:
+    GNUNET_break (0);
+    /* Note: can theoretically happen due to non-transactional nature if
+       the backup expired / was gc'ed JUST between the two SQL calls.
+       But too rare to handle properly, as doing a transaction would be
+       expensive. Just admit to failure ;-) */
+    return SH_RESPONSE_reply_internal_error (connection,
+                                             TALER_EC_SYNC_DB_FETCH_ERROR,
+                                             "unexpected empty result set (try 
again?)");
+  case SYNC_DB_ONE_RESULT:
+    /* interesting case below */
+    break;
+  }
+  resp = MHD_create_response_from_buffer (backup_size,
+                                          backup,
+                                          MHD_RESPMEM_MUST_FREE);
+  {
+    char *sig_s;
+    char *prev_s;
+    char *etag;
+
+    sig_s = GNUNET_STRINGS_data_to_string_alloc (&account_sig,
+                                                 sizeof (account_sig));
+    prev_s = GNUNET_STRINGS_data_to_string_alloc (&prev_hash,
+                                                  sizeof (prev_hash));
+    etag = GNUNET_STRINGS_data_to_string_alloc (&backup_hash,
+                                                sizeof (backup_hash));
+    GNUNET_break (MHD_YES ==
+                  MHD_add_response_header (resp,
+                                           "X-Sync-Signature",
+                                           sig_s));
+    GNUNET_break (MHD_YES ==
+                  MHD_add_response_header (resp,
+                                           "X-Sync-Previous",
+                                           prev_s));
+    GNUNET_break (MHD_YES ==
+                  MHD_add_response_header (resp,
+                                           MHD_HTTP_HEADER_ETAG,
+                                           etag));
+    GNUNET_free (etag);
+    GNUNET_free (prev_s);
+    GNUNET_free (sig_s);
+  }
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_NOT_MODIFIED,
+                            resp);
+  MHD_destroy_response (resp);
+  return ret;
 }
 
 
 /**
  * @param connection the MHD connection to handle
  * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param account public key of the account the request is for
  * @param upload_data upload data
  * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
  * @return MHD result code
@@ -48,9 +204,11 @@ sync_handler_backup_get (struct MHD_Connection *connection,
 int
 sync_handler_backup_post (struct MHD_Connection *connection,
                           void **con_cls,
-                          const char *url,
+                          const struct SYNC_AccountPublicKeyP *account,
                           const char *upload_data,
                           size_t *upload_data_size)
 {
+  struct SYNC_AccountSignatureP account_sig;
+
   return MHD_NO;
 }
diff --git a/src/sync/sync-httpd_backup.h b/src/sync/sync-httpd_backup.h
index 1ba7408..02f31be 100644
--- a/src/sync/sync-httpd_backup.h
+++ b/src/sync/sync-httpd_backup.h
@@ -24,20 +24,20 @@
 
 /**
  * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param account public key of the account the request is for
+ * @param[in,out] con_cls the connection's closure (can be updated)
  * @return MHD result code
  */
 int
 sync_handler_backup_get (struct MHD_Connection *connection,
-                         const char *url,
+                         const struct SYNC_AccountPublicKeyP *account,
                          void **con_cls);
 
 
 /**
  * @param connection the MHD connection to handle
  * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param account public key of the account the request is for
  * @param upload_data upload data
  * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
  * @return MHD result code
@@ -45,7 +45,7 @@ sync_handler_backup_get (struct MHD_Connection *connection,
 int
 sync_handler_backup_post (struct MHD_Connection *connection,
                           void **con_cls,
-                          const char *url,
+                          const struct SYNC_AccountPublicKeyP *account,
                           const char *upload_data,
                           size_t *upload_data_size);
 
diff --git a/src/syncdb/plugin_syncdb_postgres.c 
b/src/syncdb/plugin_syncdb_postgres.c
index 1d89b5d..aba58d8 100644
--- a/src/syncdb/plugin_syncdb_postgres.c
+++ b/src/syncdb/plugin_syncdb_postgres.c
@@ -258,6 +258,7 @@ postgres_store_backup (void *cls,
   struct PostgresClosure *pg = cls;
   enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_HashCode bh;
+  static struct GNUNET_HashCode no_previous_hash;
 
   check_connection (pg);
   postgres_preflight (pg);
@@ -265,6 +266,7 @@ postgres_store_backup (void *cls,
     struct GNUNET_PQ_QueryParam params[] = {
       GNUNET_PQ_query_param_auto_from_type (account_pub),
       GNUNET_PQ_query_param_auto_from_type (account_sig),
+      GNUNET_PQ_query_param_auto_from_type (&no_previous_hash),
       GNUNET_PQ_query_param_auto_from_type (backup_hash),
       GNUNET_PQ_query_param_fixed_size (backup,
                                         backup_size),
@@ -404,6 +406,7 @@ postgres_update_backup (void *cls,
     struct GNUNET_PQ_QueryParam params[] = {
       GNUNET_PQ_query_param_auto_from_type (backup_hash),
       GNUNET_PQ_query_param_auto_from_type (account_sig),
+      GNUNET_PQ_query_param_auto_from_type (old_backup_hash),
       GNUNET_PQ_query_param_fixed_size (backup,
                                         backup_size),
       GNUNET_PQ_query_param_auto_from_type (account_pub),
@@ -519,12 +522,97 @@ postgres_update_backup (void *cls,
 }
 
 
+/**
+ * Lookup an account and associated backup meta data.
+ *
+ * @param cls closure
+ * @param account_pub account to store @a backup under
+ * @param backup_hash[OUT] set to hash of @a backup
+ * @return transaction status
+ */
+static enum SYNC_DB_QueryStatus
+postgres_lookup_account (void *cls,
+                         const struct SYNC_AccountPublicKeyP *account_pub,
+                         struct GNUNET_HashCode *backup_hash)
+{
+  struct PostgresClosure *pg = cls;
+  enum GNUNET_DB_QueryStatus qs;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (account_pub),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  postgres_preflight (pg);
+  {
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
+                                            backup_hash),
+      GNUNET_PQ_result_spec_end
+    };
+
+    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "backup_select_hash",
+                                                   params,
+                                                   rs);
+  }
+  switch (qs)
+  {
+  case GNUNET_DB_STATUS_HARD_ERROR:
+    return SYNC_DB_HARD_ERROR;
+  case GNUNET_DB_STATUS_SOFT_ERROR:
+    GNUNET_break (0);
+    return SYNC_DB_SOFT_ERROR;
+  case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+    break; /* handle interesting case below */
+  case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+    return SYNC_DB_ONE_RESULT;
+  default:
+    GNUNET_break (0);
+    return SYNC_DB_HARD_ERROR;
+  }
+
+  /* check if account exists */
+  {
+    struct GNUNET_TIME_Absolute expiration;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_auto_from_type ("expiration_date",
+                                            &expiration),
+      GNUNET_PQ_result_spec_end
+    };
+
+    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "account_select",
+                                                   params,
+                                                   rs);
+  }
+  switch (qs)
+  {
+  case GNUNET_DB_STATUS_HARD_ERROR:
+    return SYNC_DB_HARD_ERROR;
+  case GNUNET_DB_STATUS_SOFT_ERROR:
+    GNUNET_break (0);
+    return SYNC_DB_SOFT_ERROR;
+  case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+    /* indicates: no account */
+    return SYNC_DB_PAYMENT_REQUIRED;
+  case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+    /* indicates: no backup */
+    return SYNC_DB_NO_RESULTS;
+  default:
+    GNUNET_break (0);
+    return SYNC_DB_HARD_ERROR;
+  }
+}
+
+
 /**
  * Obtain backup.
  *
  * @param cls closure
  * @param account_pub account to store @a backup under
  * @param account_sig[OUT] set to signature affirming storage request
+ * @param prev_hash[OUT] set to hash of previous @a backup, all zeros if none
  * @param backup_hash[OUT] set to hash of @a backup
  * @param backup_size[OUT] set to number of bytes in @a backup
  * @param backup[OUT] set to raw data to backup, caller MUST FREE
@@ -533,6 +621,7 @@ static enum SYNC_DB_QueryStatus
 postgres_lookup_backup (void *cls,
                         const struct SYNC_AccountPublicKeyP *account_pub,
                         struct SYNC_AccountSignatureP *account_sig,
+                        struct GNUNET_HashCode *prev_hash,
                         struct GNUNET_HashCode *backup_hash,
                         size_t *backup_size,
                         void **backup)
@@ -546,6 +635,8 @@ postgres_lookup_backup (void *cls,
   struct GNUNET_PQ_ResultSpec rs[] = {
     GNUNET_PQ_result_spec_auto_from_type ("account_sig",
                                           account_sig),
+    GNUNET_PQ_result_spec_auto_from_type ("prev_hash",
+                                          prev_hash),
     GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
                                           backup_hash),
     GNUNET_PQ_result_spec_variable_size ("data",
@@ -724,6 +815,7 @@ libsync_plugin_db_postgres_init (void *cls)
                             "("
                             "account_pub BYTEA PRIMARY KEY REFERENCES accounts 
(account_pub),"
                             "account_sig BYTEA NOT NULL CHECK 
(length(account_sig)=64),"
+                            "prev_hash BYTEA NOT NULL CHECK 
(length(prev_hash)=64),"
                             "backup_hash BYTEA NOT NULL CHECK 
(length(backup_hash)=64),"
                             "data BYTEA NOT NULL"
                             ");"),
@@ -766,22 +858,24 @@ libsync_plugin_db_postgres_init (void *cls)
                             "INSERT INTO backups "
                             "(account_pub"
                             ",account_sig"
+                            ",prev_hash"
                             ",backup_hash"
                             ",data"
                             ") VALUES "
-                            "($1,$2,$3,$4);",
-                            4),
+                            "($1,$2,$3,$4,$5);",
+                            5),
     GNUNET_PQ_make_prepare ("backup_update",
                             "UPDATE backups "
                             " SET"
                             " backup_hash=$1"
                             ",account_sig=$2"
-                            ",data=$3"
+                            ",prev_hash=$3"
+                            ",data=$4"
                             " WHERE"
-                            "   account_pub=$4"
+                            "   account_pub=$5"
                             "  AND"
-                            "   backup_hash=$5;",
-                            5),
+                            "   backup_hash=$6;",
+                            6),
     GNUNET_PQ_make_prepare ("backup_select_hash",
                             "SELECT "
                             " backup_hash "
@@ -793,6 +887,7 @@ libsync_plugin_db_postgres_init (void *cls)
     GNUNET_PQ_make_prepare ("backup_select",
                             "SELECT "
                             " account_sig"
+                            ",prev_hash"
                             ",backup_hash"
                             ",data "
                             "FROM"
@@ -822,6 +917,7 @@ libsync_plugin_db_postgres_init (void *cls)
   plugin->drop_tables = &postgres_drop_tables;
   plugin->gc = &postgres_gc;
   plugin->store_backup_TR = &postgres_store_backup;
+  plugin->lookup_account_TR = &postgres_lookup_account;
   plugin->lookup_backup_TR = &postgres_lookup_backup;
   plugin->update_backup_TR = &postgres_update_backup;
   plugin->increment_lifetime_TR = &postgres_increment_lifetime;

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]