summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c60
-rw-r--r--src/exchange/taler-exchange-httpd_wire.c123
-rw-r--r--src/include/taler_mhd_lib.h12
-rw-r--r--src/mhd/mhd_legal.c4
-rw-r--r--src/mhd/mhd_responses.c45
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 56fe6412b..a84849099 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 30c281b55..22b4e7cdb 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 dc68df06b..b64231352 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 64c176a93..bd596862c 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 a639f4052..7dd6824e2 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 */