diff options
| author | Christian Grothoff <christian@grothoff.org> | 2022-05-12 14:15:02 +0200 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2022-05-12 14:15:02 +0200 | 
| commit | 75d9584e280ebfb3fcb400f46942695ac6e2958e (patch) | |
| tree | afe300a9dcd4aea77ae8612ef4777ffc896cae18 | |
| parent | 6cf4a068ad58f22d1896d322fc96b59d1120a98c (diff) | |
add Etag and 'expires' to /wire
| -rw-r--r-- | src/exchange/taler-exchange-httpd_keys.c | 60 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_wire.c | 123 | ||||
| -rw-r--r-- | src/include/taler_mhd_lib.h | 12 | ||||
| -rw-r--r-- | src/mhd/mhd_legal.c | 4 | ||||
| -rw-r--r-- | src/mhd/mhd_responses.c | 45 | 
5 files changed, 145 insertions, 99 deletions
| diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c index 56fe6412..a8484909 100644 --- a/src/exchange/taler-exchange-httpd_keys.c +++ b/src/exchange/taler-exchange-httpd_keys.c @@ -1657,58 +1657,6 @@ add_denom_key_cb (void *cls,  /** - * Produce HTTP "Date:" header. - * - * @param at time to write to @a date - * @param[out] date where to write the header, with - *        at least 128 bytes available space. - */ -static void -get_date_string (struct GNUNET_TIME_Absolute at, -                 char date[128]) -{ -  static const char *const days[] = -  { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -  static const char *const mons[] = -  { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", -    "Nov", "Dec"}; -  struct tm now; -  time_t t; -#if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \ -  ! defined(HAVE_GMTIME_R) -  struct tm*pNow; -#endif - -  date[0] = 0; -  t = (time_t) (at.abs_value_us / 1000LL / 1000LL); -#if defined(HAVE_C11_GMTIME_S) -  if (NULL == gmtime_s (&t, &now)) -    return; -#elif defined(HAVE_W32_GMTIME_S) -  if (0 != gmtime_s (&now, &t)) -    return; -#elif defined(HAVE_GMTIME_R) -  if (NULL == gmtime_r (&t, &now)) -    return; -#else -  pNow = gmtime (&t); -  if (NULL == pNow) -    return; -  now = *pNow; -#endif -  sprintf (date, -           "%3s, %02u %3s %04u %02u:%02u:%02u GMT", -           days[now.tm_wday % 7], -           (unsigned int) now.tm_mday, -           mons[now.tm_mon % 12], -           (unsigned int) (1900 + now.tm_year), -           (unsigned int) now.tm_hour, -           (unsigned int) now.tm_min, -           (unsigned int) now.tm_sec); -} - - -/**   * Add the headers we want to set for every /keys response.   *   * @param ksh the key state to use @@ -1726,8 +1674,8 @@ setup_general_response_headers (struct TEH_KeyStateHandle *ksh,                  MHD_add_response_header (response,                                           MHD_HTTP_HEADER_CONTENT_TYPE,                                           "application/json")); -  get_date_string (ksh->reload_time.abs_time, -                   dat); +  TALER_MHD_get_date_string (ksh->reload_time.abs_time, +                             dat);    GNUNET_break (MHD_YES ==                  MHD_add_response_header (response,                                           MHD_HTTP_HEADER_LAST_MODIFIED, @@ -1742,8 +1690,8 @@ setup_general_response_headers (struct TEH_KeyStateHandle *ksh,                                    ksh->rekey_frequency);      a = GNUNET_TIME_relative_to_absolute (r);      m = GNUNET_TIME_absolute_to_timestamp (a); -    get_date_string (m.abs_time, -                     dat); +    TALER_MHD_get_date_string (m.abs_time, +                               dat);      GNUNET_log (GNUNET_ERROR_TYPE_INFO,                  "Setting /keys 'Expires' header to '%s'\n",                  dat); diff --git a/src/exchange/taler-exchange-httpd_wire.c b/src/exchange/taler-exchange-httpd_wire.c index 30c281b5..22b4e7cd 100644 --- a/src/exchange/taler-exchange-httpd_wire.c +++ b/src/exchange/taler-exchange-httpd_wire.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2015-2021 Taler Systems SA +  Copyright (C) 2015-2022 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU Affero General Public License as published by the Free Software @@ -72,9 +72,9 @@ struct WireFeeSet  struct WireStateHandle  {    /** -   * Cached JSON for /wire response. +   * Cached reply for /wire response.     */ -  json_t *wire_reply; +  struct MHD_Response *wire_reply;    /**     * head of DLL of wire fees. @@ -136,7 +136,7 @@ destroy_wire_state (struct WireStateHandle *wsh)      GNUNET_free (wfs->method);      GNUNET_free (wfs);    } -  json_decref (wsh->wire_reply); +  MHD_destroy_response (wsh->wire_reply);    GNUNET_free (wsh);  } @@ -204,28 +204,6 @@ TEH_wire_done ()  /** - * Create standard JSON response format using @a ec and @a detail. - * - * @param ec error code to return - * @param detail optional detail text to return, can be NULL - * @return JSON response - */ -static json_t * -make_ec_reply (enum TALER_ErrorCode ec, -               const char *detail) -{ -  return GNUNET_JSON_PACK ( -    GNUNET_JSON_pack_uint64 ("code", -                             ec), -    GNUNET_JSON_pack_string ("hint", -                             TALER_ErrorCode_get_hint (ec)), -    GNUNET_JSON_pack_allow_null ( -      GNUNET_JSON_pack_string ("detail", -                               detail))); -} - - -/**   * Add information about a wire account to @a cls.   *   * @param cls a `json_t *` object to expand with wire account details @@ -274,6 +252,18 @@ struct AddContext     * Array to append the fee to.     */    json_t *a; + +  /** +   * Context we hash "everything" we add into. This is used +   * to compute the etag. Technically, we only hash the +   * master_sigs, as they imply the rest. +   */ +  struct GNUNET_HashContext *hc; + +  /** +   * Set to the maximum end-date seen. +   */ +  struct GNUNET_TIME_Absolute max_seen;  }; @@ -297,6 +287,11 @@ add_wire_fee (void *cls,    struct AddContext *ac = cls;    struct WireFeeSet *wfs; +  GNUNET_CRYPTO_hash_context_read (ac->hc, +                                   master_sig, +                                   sizeof (*master_sig)); +  ac->max_seen = GNUNET_TIME_absolute_max (ac->max_seen, +                                           end_date.abs_time);    wfs = GNUNET_new (struct WireFeeSet);    wfs->start_date = start_date;    wfs->end_date = end_date; @@ -341,6 +336,8 @@ build_wire_state (void)    uint64_t wg = wire_generation; /* must be obtained FIRST */    enum GNUNET_DB_QueryStatus qs;    struct WireStateHandle *wsh; +  struct GNUNET_TIME_Absolute cache_expiration; +  struct GNUNET_HashContext *hc;    wsh = GNUNET_new (struct WireStateHandle);    wsh->wire_generation = wg; @@ -355,8 +352,8 @@ build_wire_state (void)      json_decref (wire_accounts_array);      wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;      wsh->wire_reply -      = make_ec_reply (TALER_EC_GENERIC_DB_FETCH_FAILED, -                       "get_wire_accounts"); +      = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED, +                              "get_wire_accounts");      return wsh;    }    if (0 == json_array_size (wire_accounts_array)) @@ -364,12 +361,14 @@ build_wire_state (void)      json_decref (wire_accounts_array);      wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;      wsh->wire_reply -      = make_ec_reply (TALER_EC_EXCHANGE_WIRE_NO_ACCOUNTS_CONFIGURED, -                       NULL); +      = TALER_MHD_make_error (TALER_EC_EXCHANGE_WIRE_NO_ACCOUNTS_CONFIGURED, +                              NULL);      return wsh;    }    wire_fee_object = json_object ();    GNUNET_assert (NULL != wire_fee_object); +  cache_expiration = GNUNET_TIME_UNIT_ZERO_ABS; +  hc = GNUNET_CRYPTO_hash_context_start ();    {      json_t *account;      size_t index; @@ -385,10 +384,12 @@ build_wire_state (void)        {          wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;          wsh->wire_reply -          = make_ec_reply (TALER_EC_EXCHANGE_WIRE_INVALID_PAYTO_CONFIGURED, -                           payto_uri); +          = TALER_MHD_make_error ( +              TALER_EC_EXCHANGE_WIRE_INVALID_PAYTO_CONFIGURED, +              payto_uri);          json_decref (wire_accounts_array);          json_decref (wire_fee_object); +        GNUNET_CRYPTO_hash_context_abort (hc);          return wsh;        }        if (NULL == json_object_get (wire_fee_object, @@ -397,7 +398,8 @@ build_wire_state (void)          struct AddContext ac = {            .wire_method = wire_method,            .wsh = wsh, -          .a = json_array () +          .a = json_array (), +          .hc = hc          };          GNUNET_assert (NULL != ac.a); @@ -414,8 +416,9 @@ build_wire_state (void)            GNUNET_free (wire_method);            wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;            wsh->wire_reply -            = make_ec_reply (TALER_EC_GENERIC_DB_FETCH_FAILED, -                             "get_wire_fees"); +            = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED, +                                    "get_wire_fees"); +          GNUNET_CRYPTO_hash_context_abort (hc);            return wsh;          }          if (0 == json_array_size (ac.a)) @@ -425,11 +428,14 @@ build_wire_state (void)            json_decref (wire_fee_object);            wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;            wsh->wire_reply -            = make_ec_reply (TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED, -                             wire_method); +            = TALER_MHD_make_error (TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED, +                                    wire_method);            GNUNET_free (wire_method); +          GNUNET_CRYPTO_hash_context_abort (hc);            return wsh;          } +        cache_expiration = GNUNET_TIME_absolute_min (ac.max_seen, +                                                     cache_expiration);          GNUNET_assert (0 ==                         json_object_set_new (wire_fee_object,                                              wire_method, @@ -438,13 +444,48 @@ build_wire_state (void)        GNUNET_free (wire_method);      }    } -  wsh->wire_reply = GNUNET_JSON_PACK ( + + +  wsh->wire_reply = TALER_MHD_MAKE_JSON_PACK (      GNUNET_JSON_pack_array_steal ("accounts",                                    wire_accounts_array),      GNUNET_JSON_pack_object_steal ("fees",                                     wire_fee_object),      GNUNET_JSON_pack_data_auto ("master_public_key",                                  &TEH_master_public_key)); +  { +    char dat[128]; +    struct GNUNET_TIME_Timestamp m; + +    m = GNUNET_TIME_absolute_to_timestamp (cache_expiration); +    TALER_MHD_get_date_string (m.abs_time, +                               dat); +    GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                "Setting 'Expires' header for '/wire' to '%s'\n", +                dat); +    GNUNET_break (MHD_YES == +                  MHD_add_response_header (wsh->wire_reply, +                                           MHD_HTTP_HEADER_EXPIRES, +                                           dat)); +  } +  TALER_MHD_add_global_headers (wsh->wire_reply); +  { +    struct GNUNET_HashCode h; +    char etag[sizeof (h) * 2]; +    char *end; + +    GNUNET_CRYPTO_hash_context_finish (hc, +                                       &h); +    end = GNUNET_STRINGS_data_to_string (&h, +                                         sizeof (h), +                                         etag, +                                         sizeof (etag)); +    *end = '\0'; +    GNUNET_break (MHD_YES == +                  MHD_add_response_header (wsh->wire_reply, +                                           MHD_HTTP_HEADER_ETAG, +                                           etag)); +  }    wsh->http_status = MHD_HTTP_OK;    return wsh;  } @@ -509,9 +550,9 @@ TEH_handler_wire (struct TEH_RequestContext *rc,                                         MHD_HTTP_INTERNAL_SERVER_ERROR,                                         TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,                                         NULL); -  return TALER_MHD_reply_json (rc->connection, -                               wsh->wire_reply, -                               wsh->http_status); +  return MHD_queue_response (rc->connection, +                             wsh->http_status, +                             wsh->wire_reply);  } diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index dc68df06..b6423135 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -208,6 +208,18 @@ TALER_MHD_reply_with_ec (struct MHD_Connection *connection,  /** + * Produce HTTP "Date:" header. + * + * @param at time to write to @a date + * @param[out] date where to write the header, with + *        at least 128 bytes available space. + */ +void +TALER_MHD_get_date_string (struct GNUNET_TIME_Absolute at, +                           char date[128]); + + +/**   * Make JSON response object.   *   * @param json the json object diff --git a/src/mhd/mhd_legal.c b/src/mhd/mhd_legal.c index 64c176a9..bd596862 100644 --- a/src/mhd/mhd_legal.c +++ b/src/mhd/mhd_legal.c @@ -178,8 +178,8 @@ TALER_MHD_reply_legal (struct MHD_Connection *conn,    a = GNUNET_TIME_relative_to_absolute (MAX_TERMS_CACHING);    m = GNUNET_TIME_absolute_to_timestamp (a); -  get_date_string (m.abs_time, -                   dat); +  TALER_MHD_get_date_string (m.abs_time, +                             dat);    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Setting 'Expires' header to '%s'\n",                dat); diff --git a/src/mhd/mhd_responses.c b/src/mhd/mhd_responses.c index a639f405..7dd6824e 100644 --- a/src/mhd/mhd_responses.c +++ b/src/mhd/mhd_responses.c @@ -502,4 +502,49 @@ TALER_MHD_reply_static (struct MHD_Connection *connection,  } +void +TALER_MHD_get_date_string (struct GNUNET_TIME_Absolute at, +                           char date[128]) +{ +  static const char *const days[] = +  { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +  static const char *const mons[] = +  { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", +    "Nov", "Dec"}; +  struct tm now; +  time_t t; +#if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \ +  ! defined(HAVE_GMTIME_R) +  struct tm*pNow; +#endif + +  date[0] = 0; +  t = (time_t) (at.abs_value_us / 1000LL / 1000LL); +#if defined(HAVE_C11_GMTIME_S) +  if (NULL == gmtime_s (&t, &now)) +    return; +#elif defined(HAVE_W32_GMTIME_S) +  if (0 != gmtime_s (&now, &t)) +    return; +#elif defined(HAVE_GMTIME_R) +  if (NULL == gmtime_r (&t, &now)) +    return; +#else +  pNow = gmtime (&t); +  if (NULL == pNow) +    return; +  now = *pNow; +#endif +  sprintf (date, +           "%3s, %02u %3s %04u %02u:%02u:%02u GMT", +           days[now.tm_wday % 7], +           (unsigned int) now.tm_mday, +           mons[now.tm_mon % 12], +           (unsigned int) (1900 + now.tm_year), +           (unsigned int) now.tm_hour, +           (unsigned int) now.tm_min, +           (unsigned int) now.tm_sec); +} + +  /* end of mhd_responses.c */ | 
