From bb2b8f9936f1e4c39b0c1c7495f7ae08d35aff88 Mon Sep 17 00:00:00 2001 From: Christian Blättler Date: Tue, 19 Dec 2023 08:35:50 +0100 Subject: refactor phases and parsing logic --- .../taler-merchant-httpd_private-post-orders.c | 514 ++++++++++----------- 1 file changed, 244 insertions(+), 270 deletions(-) (limited to 'src/backend') diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c index 9d00b0b9..9090b317 100644 --- a/src/backend/taler-merchant-httpd_private-post-orders.c +++ b/src/backend/taler-merchant-httpd_private-post-orders.c @@ -137,7 +137,7 @@ struct RekeyExchange struct OrderContext { /** - * Information set in the ORDER_PHASE_INIT phase. + * Information set in the ORDER_PHASE_PARSE_REQUEST phase. */ struct { /** @@ -178,7 +178,9 @@ struct OrderContext unsigned int inventory_products_length; /** - * Array of inventory products in the @e order. + * Specifies that some products are to be included in the + * order from the inventory. For these inventory management + * is performed (so the products must be in stock). */ struct InventoryProduct *inventory_products; @@ -197,19 +199,9 @@ struct OrderContext */ struct TALER_ClaimTokenP claim_token; - } init; + } parse_request; - /** - * Information set in the ORDER_PHASE_MERGE_INVENTORY phase. - */ - struct { - /** - * Merged array of products in the @e order. - */ - json_t *products; - } merge_inventory; - /** * Information set in the ORDER_PHASE_ADD_PAYMENT_DETAILS phase. */ @@ -222,7 +214,7 @@ struct OrderContext } add_payment_details; /** - * Information set in the ORDER_PHASE_PATCH_ORDER phase. + * Information set in the ORDER_PHASE_PARSE_ORDER phase. */ struct { /** @@ -277,6 +269,16 @@ struct OrderContext */ struct GNUNET_TIME_Timestamp refund_deadline; + /** + * Payment deadline. + */ + struct GNUNET_TIME_Timestamp pay_deadline; + + /** + * Wire transfer deadline. + */ + struct GNUNET_TIME_Timestamp wire_deadline; + /** * Delivery date. */ @@ -288,14 +290,9 @@ struct OrderContext json_t *delivery_location; /** - * Payment deadline. - */ - struct GNUNET_TIME_Timestamp pay_deadline; - - /** - * Wire transfer deadline. + * Array of products that are part of the purchase. */ - struct GNUNET_TIME_Timestamp wire_deadline; + const json_t *products; /** * TODO: Maybe remove this and set it from settings where we serialize @@ -341,7 +338,17 @@ struct OrderContext */ json_t *extra; - } patch_order; + } parse_order; + + /** + * Information set in the ORDER_PHASE_MERGE_INVENTORY phase. + */ + struct { + /** + * Merged array of products in the @e order. + */ + json_t *products; + } merge_inventory; /** * Information set in the ORDER_PHASE_SET_EXCHANGES phase. @@ -443,10 +450,10 @@ struct OrderContext */ enum { - ORDER_PHASE_INIT, + ORDER_PHASE_PARSE_REQUEST, + ORDER_PHASE_PARSE_ORDER, ORDER_PHASE_MERGE_INVENTORY, ORDER_PHASE_ADD_PAYMENT_DETAILS, - ORDER_PHASE_PATCH_ORDER, ORDER_PHASE_SET_EXCHANGES, ORDER_PHASE_SET_MAX_FEE, ORDER_PHASE_SERIALIZE_ORDER, @@ -581,13 +588,13 @@ clean_order (void *cls) json_decref (oc->set_exchanges.exchanges); oc->set_exchanges.exchanges = NULL; } - GNUNET_array_grow (oc->init.inventory_products, - oc->init.inventory_products_length, + GNUNET_array_grow (oc->parse_request.inventory_products, + oc->parse_request.inventory_products_length, 0); - GNUNET_array_grow (oc->init.uuids, - oc->init.uuids_length, + GNUNET_array_grow (oc->parse_request.uuids, + oc->parse_request.uuids_length, 0); - json_decref (oc->init.order); + json_decref (oc->parse_request.order); /* TODO: Check that all other fields are cleaned up! */ json_decref (oc->serialize_order.contract); GNUNET_free (oc); @@ -617,14 +624,14 @@ execute_transaction (struct OrderContext *oc) /* Setup order */ qs = TMH_db->insert_order (TMH_db->cls, oc->hc->instance->settings.id, - oc->patch_order.order_id, + oc->parse_order.order_id, NULL /* session ID! FIXME: protocol v6! */, - &oc->init.h_post_data, - oc->patch_order.pay_deadline, - &oc->init.claim_token, + &oc->parse_request.h_post_data, + oc->parse_order.pay_deadline, + &oc->parse_request.claim_token, oc->serialize_order.contract, /* called 'contract terms' at database. */ - oc->init.pos_key, - oc->init.pos_algorithm); + oc->parse_request.pos_key, + oc->parse_request.pos_algorithm); if (qs <= 0) { /* qs == 0: probably instance does not exist (anymore) */ @@ -632,10 +639,10 @@ execute_transaction (struct OrderContext *oc) return qs; } /* Migrate locks from UUIDs to new order: first release old locks */ - for (unsigned int i = 0; iinit.uuids_length; i++) + for (unsigned int i = 0; iparse_request.uuids_length; i++) { qs = TMH_db->unlock_inventory (TMH_db->cls, - &oc->init.uuids[i]); + &oc->parse_request.uuids[i]); if (qs < 0) { TMH_db->rollback (TMH_db->cls); @@ -648,14 +655,14 @@ execute_transaction (struct OrderContext *oc) (note: this can basically ONLY fail on serializability OR because the UUID locks were insufficient for the desired quantities). */ - for (unsigned int i = 0; iinit.inventory_products_length; i++) + for (unsigned int i = 0; iparse_request.inventory_products_length; i++) { qs = TMH_db->insert_order_lock ( TMH_db->cls, oc->hc->instance->settings.id, - oc->patch_order.order_id, - oc->init.inventory_products[i].product_id, - oc->init.inventory_products[i].quantity); + oc->parse_order.order_id, + oc->parse_request.inventory_products[i].product_id, + oc->parse_request.inventory_products[i].quantity); if (qs < 0) { TMH_db->rollback (TMH_db->cls); @@ -675,7 +682,7 @@ execute_transaction (struct OrderContext *oc) update long-poll clients. */ qs = TMH_db->lookup_order_summary (TMH_db->cls, oc->hc->instance->settings.id, - oc->patch_order.order_id, + oc->parse_order.order_id, ×tamp, &order_serial); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) @@ -708,42 +715,6 @@ execute_order (struct OrderContext *oc) { const struct TALER_MERCHANTDB_InstanceSettings *settings = &oc->hc->instance->settings; - // const char *summary; - // const char *fulfillment_msg = NULL; - // const json_t *products; - // This was never actually used, not even checked if it is well-formed. - // const json_t *merchant; - // struct GNUNET_TIME_Timestamp timestamp; - // struct GNUNET_TIME_Timestamp refund_deadline = { 0 }; - // struct GNUNET_TIME_Timestamp wire_transfer_deadline; - // struct GNUNET_JSON_Specification spec[] = { - // GNUNET_JSON_spec_string ("order_id", - // &oc->patch_order.order_id), - // TALER_JSON_spec_i18n_str ("summary", - // &summary), - /** - * The following entries we don't actually need, - * except to check that the order is well-formed */ - // GNUNET_JSON_spec_array_const ("products", - // &products), - // GNUNET_JSON_spec_object_const ("merchant", - // &merchant), - // GNUNET_JSON_spec_mark_optional ( - // TALER_JSON_spec_i18n_str ("fulfillment_message", - // &fulfillment_msg), - // NULL), - // GNUNET_JSON_spec_timestamp ("timestamp", - // ×tamp), - // GNUNET_JSON_spec_mark_optional ( - // GNUNET_JSON_spec_timestamp ("refund_deadline", - // &refund_deadline), - // NULL), - // GNUNET_JSON_spec_timestamp ("pay_deadline", - // &oc->patch_order.pay_deadline), - // GNUNET_JSON_spec_timestamp ("wire_transfer_deadline", - // &wire_transfer_deadline), - // GNUNET_JSON_spec_end () - // }; enum GNUNET_DB_QueryStatus qs; /* extract fields we need to sign separately */ @@ -765,7 +736,6 @@ execute_order (struct OrderContext *oc) /* check product list in contract is well-formed */ if (! TMH_products_array_valid (oc->merge_inventory.products)) { - // GNUNET_JSON_parse_free (spec); GNUNET_break_op (0); reply_with_error (oc, MHD_HTTP_BAD_REQUEST, @@ -783,7 +753,7 @@ execute_order (struct OrderContext *oc) TMH_db->preflight (TMH_db->cls); qs = TMH_db->lookup_order (TMH_db->cls, oc->hc->instance->settings.id, - oc->patch_order.order_id, + oc->parse_order.order_id, &token, &orig_post, &contract_terms); @@ -792,7 +762,6 @@ execute_order (struct OrderContext *oc) { GNUNET_break (0); TMH_db->rollback (TMH_db->cls); - // GNUNET_JSON_parse_free (spec); reply_with_error (oc, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, @@ -807,7 +776,7 @@ execute_order (struct OrderContext *oc) /* Comparing the contract terms is sufficient because all the other params get added to it at some point. */ if (0 == GNUNET_memcmp (&orig_post, - &oc->init.h_post_data)) + &oc->parse_request.h_post_data)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Order creation idempotent\n"); @@ -815,7 +784,7 @@ execute_order (struct OrderContext *oc) oc->connection, MHD_HTTP_OK, GNUNET_JSON_pack_string ("order_id", - oc->patch_order.order_id), + oc->parse_order.order_id), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_data_varsize ( "token", @@ -823,7 +792,6 @@ execute_order (struct OrderContext *oc) ? NULL : &token, sizeof (token)))); - // GNUNET_JSON_parse_free (spec); finalize_order (oc, ret); return; @@ -834,14 +802,13 @@ execute_order (struct OrderContext *oc) oc, MHD_HTTP_CONFLICT, TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS, - oc->patch_order.order_id); - // GNUNET_JSON_parse_free (spec); + oc->parse_order.order_id); return; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing database transaction to create order '%s' for instance '%s'\n", - oc->patch_order.order_id, + oc->parse_order.order_id, settings->id); for (unsigned int i = 0; i= qs) { - // GNUNET_JSON_parse_free (spec); /* Special report if retries insufficient */ if (GNUNET_DB_STATUS_SOFT_ERROR == qs) { @@ -871,7 +837,7 @@ execute_order (struct OrderContext *oc) oc, MHD_HTTP_CONFLICT, TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS, - oc->patch_order.order_id); + oc->parse_order.order_id); return; } /* Other hard transaction error (disk full, etc.) */ @@ -898,9 +864,8 @@ execute_order (struct OrderContext *oc) qs = TMH_db->lookup_product ( TMH_db->cls, oc->hc->instance->settings.id, - oc->init.inventory_products[oc->execute_order.out_of_stock_index].product_id, + oc->parse_request.inventory_products[oc->execute_order.out_of_stock_index].product_id, &pd); - // GNUNET_JSON_parse_free (spec); switch (qs) { case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: @@ -911,10 +876,10 @@ execute_order (struct OrderContext *oc) MHD_HTTP_GONE, GNUNET_JSON_pack_string ( "product_id", - oc->init.inventory_products[oc->execute_order.out_of_stock_index].product_id), + oc->parse_request.inventory_products[oc->execute_order.out_of_stock_index].product_id), GNUNET_JSON_pack_uint64 ( "requested_quantity", - oc->init.inventory_products[oc->execute_order.out_of_stock_index].quantity), + oc->parse_request.inventory_products[oc->execute_order.out_of_stock_index].quantity), GNUNET_JSON_pack_uint64 ( "available_quantity", pd.total_stock - pd.total_sold - pd.total_lost), @@ -935,11 +900,11 @@ execute_order (struct OrderContext *oc) MHD_HTTP_GONE, GNUNET_JSON_pack_string ( "product_id", - oc->init.inventory_products[oc->execute_order.out_of_stock_index]. + oc->parse_request.inventory_products[oc->execute_order.out_of_stock_index]. product_id), GNUNET_JSON_pack_uint64 ( "requested_quantity", - oc->init.inventory_products[oc->execute_order.out_of_stock_index]. + oc->parse_request.inventory_products[oc->execute_order.out_of_stock_index]. quantity), GNUNET_JSON_pack_uint64 ( "available_quantity", @@ -977,15 +942,14 @@ execute_order (struct OrderContext *oc) oc->connection, MHD_HTTP_OK, GNUNET_JSON_pack_string ("order_id", - oc->patch_order.order_id), + oc->parse_order.order_id), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_data_varsize ( "token", - GNUNET_is_zero (&oc->init.claim_token) + GNUNET_is_zero (&oc->parse_request.claim_token) ? NULL - : &oc->init.claim_token, - sizeof (oc->init.claim_token)))); - // GNUNET_JSON_parse_free (spec); + : &oc->parse_request.claim_token, + sizeof (oc->parse_request.claim_token)))); finalize_order (oc, ret); } @@ -993,7 +957,8 @@ execute_order (struct OrderContext *oc) /** - * Check that the contract is now well-formed. + * Check that the contract is now well-formed. Upon success, continue + * processing with execute_order(). * * @param[in,out] oc order context */ @@ -1011,7 +976,7 @@ check_contract (struct OrderContext *oc) oc, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH, - "could not compute hash of patched order"); + "could not compute hash of serialized order"); return; case GNUNET_NO: GNUNET_break_op (0); @@ -1043,23 +1008,23 @@ update_stefan (struct OrderContext *oc, if (GNUNET_SYSERR != TALER_EXCHANGE_keys_stefan_b2n (keys, - &oc->patch_order.brutto, + &oc->parse_order.brutto, &net)) { struct TALER_Amount fee; TALER_EXCHANGE_keys_stefan_round (keys, &net); - if (-1 == TALER_amount_cmp (&oc->patch_order.brutto, + if (-1 == TALER_amount_cmp (&oc->parse_order.brutto, &net)) { /* brutto < netto! */ /* => after rounding, there is no real difference */ - net = oc->patch_order.brutto; + net = oc->parse_order.brutto; } GNUNET_assert (0 <= TALER_amount_subtract (&fee, - &oc->patch_order.brutto, + &oc->parse_order.brutto, &net)); if ( (GNUNET_OK != TALER_amount_is_valid (&oc->set_exchanges.max_stefan_fee)) || @@ -1190,7 +1155,7 @@ keys_cb ( rx->url); if ( (settings->use_stefan) && (GNUNET_OK != - TALER_amount_is_valid (&oc->patch_order.max_fee)) ) + TALER_amount_is_valid (&oc->parse_order.max_fee)) ) update_stefan (oc, keys); get_acceptable (oc, @@ -1240,7 +1205,9 @@ get_exchange_keys (void *cls, /** - * Serialize @a oc->init.order into @a oc->execute_order.contract_terms. + * Serialize order into @a oc->serialize_order.contract, + * ready to be stored in the database. Upon success, continue + * processing with check_contract(). * * @param[in,out] oc order context */ @@ -1249,22 +1216,22 @@ serialize_order (struct OrderContext *oc) { oc->serialize_order.contract = GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("summary", - oc->patch_order.summary), + oc->parse_order.summary), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_object_steal ("summary_i18n", - oc->patch_order.summary_i18n)), + oc->parse_order.summary_i18n)), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_string ("public_reorder_url", - oc->patch_order.public_reorder_url)), + oc->parse_order.public_reorder_url)), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_string ("fulfillment_message", - oc->patch_order.fulfillment_message)), + oc->parse_order.fulfillment_message)), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_object_steal ("fulfillment_message_i18n", - oc->patch_order.fulfillment_message_i18n)), + oc->parse_order.fulfillment_message_i18n)), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_string ("fulfillment_url", - oc->patch_order.fulfillment_url)), + oc->parse_order.fulfillment_url)), GNUNET_JSON_pack_array_steal ("products", oc->merge_inventory.products), GNUNET_JSON_pack_data_auto ("h_wire", @@ -1272,23 +1239,23 @@ serialize_order (struct OrderContext *oc) GNUNET_JSON_pack_string ("wire_method", oc->add_payment_details.wm->wire_method), GNUNET_JSON_pack_string ("order_id", - oc->patch_order.order_id), + oc->parse_order.order_id), GNUNET_JSON_pack_timestamp ("timestamp", - oc->patch_order.timestamp), + oc->parse_order.timestamp), GNUNET_JSON_pack_timestamp ("pay_deadline", - oc->patch_order.pay_deadline), + oc->parse_order.pay_deadline), GNUNET_JSON_pack_timestamp ("wire_transfer_deadline", - oc->patch_order.wire_deadline), + oc->parse_order.wire_deadline), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_timestamp ("delivery_date", - oc->patch_order.delivery_date)), + oc->parse_order.delivery_date)), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_object_steal ("delivery_location", - oc->patch_order.delivery_location)), + oc->parse_order.delivery_location)), GNUNET_JSON_pack_string ("merchant_base_url", - oc->patch_order.merchant_base_url), + oc->parse_order.merchant_base_url), GNUNET_JSON_pack_object_steal ("merchant", - oc->patch_order.merchant), + oc->parse_order.merchant), GNUNET_JSON_pack_data_auto ("merchant_pub", &oc->hc->instance->merchant_pub), GNUNET_JSON_pack_array_steal ("exchanges", @@ -1296,10 +1263,10 @@ serialize_order (struct OrderContext *oc) TALER_JSON_pack_amount ("max_fee", &oc->set_max_fee.max_fee), TALER_JSON_pack_amount ("amount", - &oc->patch_order.brutto), + &oc->parse_order.brutto), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_object_steal ("extra", - oc->patch_order.extra)) + oc->parse_order.extra)) ); /* Pack does not work here, because it doesn't set zero-values for timestamps */ @@ -1307,14 +1274,16 @@ serialize_order (struct OrderContext *oc) json_object_set_new (oc->serialize_order.contract, "refund_deadline", GNUNET_JSON_from_timestamp ( - oc->patch_order.refund_deadline))); + oc->parse_order.refund_deadline))); - if (!GNUNET_TIME_relative_is_zero(oc->patch_order.auto_refund)) { + /* Pack does not work here, because it sets zero-values for relative times */ + /* auto_refund should only be set if it is not 0 */ + if (!GNUNET_TIME_relative_is_zero(oc->parse_order.auto_refund)) { GNUNET_assert (0 == json_object_set_new (oc->serialize_order.contract, "auto_refund", GNUNET_JSON_from_time_rel ( - oc->patch_order.auto_refund))); + oc->parse_order.auto_refund))); } oc->phase++; @@ -1323,7 +1292,8 @@ serialize_order (struct OrderContext *oc) /** * Set max_fee in @a oc based on STEFAN value if - * not yet present. + * not yet present. Upon success, continue + * processing with serialize_order(). * * @param[in,out] oc order context */ @@ -1334,7 +1304,7 @@ set_max_fee (struct OrderContext *oc) &oc->hc->instance->settings; if (GNUNET_OK != - TALER_amount_is_valid (&oc->patch_order.max_fee)) + TALER_amount_is_valid (&oc->parse_order.max_fee)) { struct TALER_Amount stefan; @@ -1344,7 +1314,7 @@ set_max_fee (struct OrderContext *oc) stefan = oc->set_exchanges.max_stefan_fee; else GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (oc->patch_order.brutto.currency, + TALER_amount_set_zero (oc->parse_order.brutto.currency, &stefan)); oc->set_max_fee.max_fee = stefan; } @@ -1353,7 +1323,8 @@ set_max_fee (struct OrderContext *oc) /** - * Set list of acceptable exchanges in @a oc. + * Set list of acceptable exchanges in @a oc. Upon success, continue + * processing with set_max_fee(). * * @param[in,out] oc order context * @return true to suspend execution @@ -1415,28 +1386,33 @@ set_exchanges (struct OrderContext *oc) /** - * Add missing fields to the order. Upon success, continue - * processing with execute_order(). + * Add missing fields to the order. Upon success, continue + * processing with merge_inventory(). * * @param[in,out] oc order context */ static void -patch_order (struct OrderContext *oc) +parse_order (struct OrderContext *oc) { const struct TALER_MERCHANTDB_InstanceSettings *settings = &oc->hc->instance->settings; - /* Setting default values of patch_order, maybe not needed (?) */ - oc->patch_order.order_id = NULL; - oc->patch_order.fulfillment_url = NULL; - oc->patch_order.merchant_base_url = NULL; - oc->patch_order.timestamp = GNUNET_TIME_UNIT_ZERO_TS; - oc->patch_order.refund_deadline = GNUNET_TIME_UNIT_FOREVER_TS; - oc->patch_order.auto_refund = GNUNET_TIME_UNIT_ZERO; - oc->patch_order.pay_deadline = GNUNET_TIME_UNIT_ZERO_TS; - oc->patch_order.wire_deadline = GNUNET_TIME_UNIT_FOREVER_TS; - oc->patch_order.delivery_location = NULL; - + oc->parse_order.order_id = NULL; + oc->parse_order.summary_i18n = NULL; + oc->parse_order.public_reorder_url = NULL; + oc->parse_order.fulfillment_message = NULL; + oc->parse_order.fulfillment_message_i18n = NULL; + oc->parse_order.fulfillment_url = NULL; + oc->parse_order.merchant_base_url = NULL; + oc->parse_order.timestamp = GNUNET_TIME_UNIT_ZERO_TS; + oc->parse_order.refund_deadline = GNUNET_TIME_UNIT_FOREVER_TS; + oc->parse_order.pay_deadline = GNUNET_TIME_UNIT_ZERO_TS; + oc->parse_order.wire_deadline = GNUNET_TIME_UNIT_FOREVER_TS; + oc->parse_order.delivery_location = NULL; + oc->parse_order.delivery_date = GNUNET_TIME_UNIT_ZERO_TS; + oc->parse_order.products = NULL; + oc->parse_order.auto_refund = GNUNET_TIME_UNIT_ZERO; + oc->parse_order.extra = NULL; const json_t *jmerchant = NULL; /* auto_refund only needs to be type-checked, @@ -1444,88 +1420,86 @@ patch_order (struct OrderContext *oc) * be negative. */ bool no_fee; struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount_any ("amount", + &oc->parse_order.brutto), GNUNET_JSON_spec_string("summary", - &oc->patch_order.summary), + &oc->parse_order.summary), + GNUNET_JSON_spec_array_const ("products", + &oc->parse_order.products), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_json ("summary_i18n", - &oc->patch_order.summary_i18n), + &oc->parse_order.summary_i18n), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("order_id", + &oc->parse_order.order_id), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("public_reorder_url", - &oc->patch_order.public_reorder_url), + &oc->parse_order.public_reorder_url), NULL), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string("fulfillment_message", - &oc->patch_order.fulfillment_message), + GNUNET_JSON_spec_string("fulfillment_message", + &oc->parse_order.fulfillment_message), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_json ("fulfillment_message_i18n", - &oc->patch_order.fulfillment_message_i18n), + &oc->parse_order.fulfillment_message_i18n), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("fulfillment_url", + &oc->parse_order.fulfillment_url), NULL), GNUNET_JSON_spec_mark_optional ( TALER_JSON_spec_web_url ("merchant_base_url", - &oc->patch_order.merchant_base_url), + &oc->parse_order.merchant_base_url), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_object_const ("merchant", &jmerchant), NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("order_id", - &oc->patch_order.order_id), - NULL), - TALER_JSON_spec_amount_any ("amount", - &oc->patch_order.brutto), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("fulfillment_url", - &oc->patch_order.fulfillment_url), - NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_timestamp ("timestamp", - &oc->patch_order.timestamp), + &oc->parse_order.timestamp), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_timestamp ("refund_deadline", - &oc->patch_order.refund_deadline), + &oc->parse_order.refund_deadline), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_timestamp ("pay_deadline", - &oc->patch_order.pay_deadline), + &oc->parse_order.pay_deadline), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_timestamp ("wire_transfer_deadline", - &oc->patch_order.wire_deadline), + &oc->parse_order.wire_deadline), NULL), GNUNET_JSON_spec_mark_optional ( TALER_JSON_spec_amount_any ("max_fee", - &oc->patch_order.max_fee), + &oc->parse_order.max_fee), &no_fee), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_json ("delivery_location", - &oc->patch_order.delivery_location), + &oc->parse_order.delivery_location), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_timestamp ("delivery_date", - &oc->patch_order.delivery_date), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("nonce", - &oc->patch_order.nonce), + &oc->parse_order.delivery_date), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_relative_time ("auto_refund", - &oc->patch_order.auto_refund), + &oc->parse_order.auto_refund), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_json ("extra", - &oc->patch_order.extra), + &oc->parse_order.extra), NULL), GNUNET_JSON_spec_end () }; enum GNUNET_GenericReturnValue ret; ret = TALER_MHD_parse_json_data (oc->connection, - oc->init.order, + oc->parse_request.order, spec); if (GNUNET_OK != ret) { @@ -1534,7 +1508,7 @@ patch_order (struct OrderContext *oc) ret); return; } - if (! TMH_test_exchange_configured_for_currency (oc->patch_order.brutto.currency)) + if (! TMH_test_exchange_configured_for_currency (oc->parse_order.brutto.currency)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); @@ -1546,8 +1520,8 @@ patch_order (struct OrderContext *oc) } if ( (! no_fee) && (GNUNET_OK != - TALER_amount_cmp_currency (&oc->patch_order.brutto, - &oc->patch_order.max_fee)) ) + TALER_amount_cmp_currency (&oc->parse_order.brutto, + &oc->parse_order.max_fee)) ) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); @@ -1559,7 +1533,7 @@ patch_order (struct OrderContext *oc) } /* Add order_id if it doesn't exist. */ - if (NULL == oc->patch_order.order_id) + if (NULL == oc->parse_order.order_id) { char buf[256]; time_t timer; @@ -1600,16 +1574,16 @@ patch_order (struct OrderContext *oc) "Assigning order ID `%s' server-side\n", buf); - oc->patch_order.order_id = GNUNET_strdup (buf); - GNUNET_assert (NULL != oc->patch_order.order_id); + oc->parse_order.order_id = GNUNET_strdup (buf); + GNUNET_assert (NULL != oc->parse_order.order_id); } /* Patch fulfillment URL with order_id (implements #6467). */ - if (NULL != oc->patch_order.fulfillment_url) + if (NULL != oc->parse_order.fulfillment_url) { const char *pos; - pos = strstr (oc->patch_order.fulfillment_url, + pos = strstr (oc->parse_order.fulfillment_url, "${ORDER_ID}"); if (NULL != pos) { @@ -1631,14 +1605,14 @@ patch_order (struct OrderContext *oc) GNUNET_asprintf (&nurl, "%.*s%s%s", /* first output URL until ${ORDER_ID} */ - (int) (pos - oc->patch_order.fulfillment_url), - oc->patch_order.fulfillment_url, + (int) (pos - oc->parse_order.fulfillment_url), + oc->parse_order.fulfillment_url, /* replace ${ORDER_ID} with the right order_id */ - oc->patch_order.order_id, + oc->parse_order.order_id, /* append rest of original URL */ pos + strlen ("${ORDER_ID}")); - oc->patch_order.fulfillment_url = GNUNET_strdup (nurl); + oc->parse_order.fulfillment_url = GNUNET_strdup (nurl); GNUNET_free (nurl); } @@ -1650,28 +1624,28 @@ patch_order (struct OrderContext *oc) struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); /* Add timestamp if it doesn't exist (or is zero) */ - if (GNUNET_TIME_absolute_is_zero (oc->patch_order.timestamp.abs_time)) + if (GNUNET_TIME_absolute_is_zero (oc->parse_order.timestamp.abs_time)) { - oc->patch_order.timestamp = now; + oc->parse_order.timestamp = now; } /* If no refund_deadline given, set one based on refund_delay. */ - if (GNUNET_TIME_absolute_is_never (oc->patch_order.refund_deadline.abs_time)) + if (GNUNET_TIME_absolute_is_never (oc->parse_order.refund_deadline.abs_time)) { - if (GNUNET_TIME_relative_is_zero (oc->init.refund_delay)) + if (GNUNET_TIME_relative_is_zero (oc->parse_request.refund_delay)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Refund delay is zero, no refunds are possible for this order\n"); - oc->patch_order.refund_deadline = GNUNET_TIME_UNIT_ZERO_TS; + oc->parse_order.refund_deadline = GNUNET_TIME_UNIT_ZERO_TS; } else { - oc->patch_order.refund_deadline = GNUNET_TIME_relative_to_timestamp (oc->init.refund_delay); + oc->parse_order.refund_deadline = GNUNET_TIME_relative_to_timestamp (oc->parse_request.refund_delay); } } - if ( (! GNUNET_TIME_absolute_is_zero (oc->patch_order.delivery_date.abs_time)) && - (GNUNET_TIME_absolute_is_past (oc->patch_order.delivery_date.abs_time)) ) + if ( (! GNUNET_TIME_absolute_is_zero (oc->parse_order.delivery_date.abs_time)) && + (GNUNET_TIME_absolute_is_past (oc->parse_order.delivery_date.abs_time)) ) { GNUNET_break_op (0); reply_with_error ( @@ -1683,12 +1657,12 @@ patch_order (struct OrderContext *oc) } } - if (GNUNET_TIME_absolute_is_zero (oc->patch_order.pay_deadline.abs_time)) + if (GNUNET_TIME_absolute_is_zero (oc->parse_order.pay_deadline.abs_time)) { - oc->patch_order.pay_deadline = GNUNET_TIME_relative_to_timestamp ( + oc->parse_order.pay_deadline = GNUNET_TIME_relative_to_timestamp ( settings->default_pay_delay); } - else if (GNUNET_TIME_absolute_is_past (oc->patch_order.pay_deadline.abs_time)) + else if (GNUNET_TIME_absolute_is_past (oc->parse_order.pay_deadline.abs_time)) { GNUNET_break_op (0); reply_with_error ( @@ -1699,8 +1673,8 @@ patch_order (struct OrderContext *oc) return; } - if ( (! GNUNET_TIME_absolute_is_zero (oc->patch_order.refund_deadline.abs_time)) && - (GNUNET_TIME_absolute_is_past (oc->patch_order.refund_deadline.abs_time)) ) + if ( (! GNUNET_TIME_absolute_is_zero (oc->parse_order.refund_deadline.abs_time)) && + (GNUNET_TIME_absolute_is_past (oc->parse_order.refund_deadline.abs_time)) ) { GNUNET_break_op (0); reply_with_error ( @@ -1711,16 +1685,16 @@ patch_order (struct OrderContext *oc) return; } - if (GNUNET_TIME_absolute_is_never (oc->patch_order.wire_deadline.abs_time)) + if (GNUNET_TIME_absolute_is_never (oc->parse_order.wire_deadline.abs_time)) { struct GNUNET_TIME_Timestamp t; t = GNUNET_TIME_relative_to_timestamp ( GNUNET_TIME_relative_max (settings->default_wire_transfer_delay, - oc->init.refund_delay)); - oc->patch_order.wire_deadline = GNUNET_TIME_timestamp_max (oc->patch_order.refund_deadline, + oc->parse_request.refund_delay)); + oc->parse_order.wire_deadline = GNUNET_TIME_timestamp_max (oc->parse_order.refund_deadline, t); - if (GNUNET_TIME_absolute_is_never (oc->patch_order.wire_deadline.abs_time)) + if (GNUNET_TIME_absolute_is_never (oc->parse_order.wire_deadline.abs_time)) { GNUNET_break_op (0); reply_with_error ( @@ -1731,9 +1705,9 @@ patch_order (struct OrderContext *oc) return; } } - if (GNUNET_TIME_timestamp_cmp (oc->patch_order.wire_deadline, + if (GNUNET_TIME_timestamp_cmp (oc->parse_order.wire_deadline, <, - oc->patch_order.refund_deadline)) + oc->parse_order.refund_deadline)) { GNUNET_break_op (0); reply_with_error ( @@ -1744,7 +1718,7 @@ patch_order (struct OrderContext *oc) return; } - if (NULL == oc->patch_order.merchant_base_url) + if (NULL == oc->parse_order.merchant_base_url) { char *url; @@ -1760,11 +1734,11 @@ patch_order (struct OrderContext *oc) "order:merchant_base_url"); return; } - oc->patch_order.merchant_base_url = GNUNET_strdup (url); + oc->parse_order.merchant_base_url = GNUNET_strdup (url); GNUNET_free (url); } - else if (('\0' == *oc->patch_order.merchant_base_url) || - ('/' != oc->patch_order.merchant_base_url[strlen (oc->patch_order.merchant_base_url) - 1])) + else if (('\0' == *oc->parse_order.merchant_base_url) || + ('/' != oc->parse_order.merchant_base_url[strlen (oc->parse_order.merchant_base_url) - 1])) { GNUNET_break_op (0); reply_with_error ( @@ -1775,6 +1749,20 @@ patch_order (struct OrderContext *oc) return; } + if (NULL == oc->parse_order.products) + { + oc->parse_order.products = json_array (); + } + else if (! TMH_products_array_valid (oc->parse_order.products)) + { + reply_with_error ( + oc, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "order.products"); + return; + } + /* Merchant information must not already be present */ if (NULL != jmerchant) { @@ -1788,7 +1776,7 @@ patch_order (struct OrderContext *oc) } { - oc->patch_order.merchant = GNUNET_JSON_PACK ( + oc->parse_order.merchant = GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("name", settings->name), GNUNET_JSON_pack_allow_null ( @@ -1800,7 +1788,7 @@ patch_order (struct OrderContext *oc) GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_string ("logo", settings->logo))); - GNUNET_assert (NULL != oc->patch_order.merchant); + GNUNET_assert (NULL != oc->parse_order.merchant); { json_t *loca; @@ -1810,7 +1798,7 @@ patch_order (struct OrderContext *oc) { loca = json_deep_copy (loca); GNUNET_assert (0 == - json_object_set_new (oc->patch_order.merchant, + json_object_set_new (oc->parse_order.merchant, "address", loca)); } @@ -1824,14 +1812,14 @@ patch_order (struct OrderContext *oc) { locj = json_deep_copy (locj); GNUNET_assert (0 == - json_object_set_new (oc->patch_order.merchant, + json_object_set_new (oc->parse_order.merchant, "jurisdiction", locj)); } } } - oc->patch_order.merchant_pub = oc->hc->instance->merchant_pub; + oc->parse_order.merchant_pub = oc->hc->instance->merchant_pub; /* TODO: Not sure yet how to properly handle this in the refactored code */ // if (GNUNET_OK != @@ -1845,8 +1833,8 @@ patch_order (struct OrderContext *oc) // return; // } - if ( (NULL != oc->patch_order.delivery_location) && - (! TMH_location_object_valid (oc->patch_order.delivery_location)) ) + if ( (NULL != oc->parse_order.delivery_location) && + (! TMH_location_object_valid (oc->parse_order.delivery_location)) ) { GNUNET_break_op (0); reply_with_error (oc, @@ -1863,7 +1851,7 @@ patch_order (struct OrderContext *oc) /** * Process the @a payment_target and add the details of how the * order could be paid to @a order. On success, continue - * processing with patch_order(). + * processing with set_exchanges(). * * @param[in,out] oc order context */ @@ -1876,8 +1864,8 @@ add_payment_details (struct OrderContext *oc) /* Locate wire method that has a matching payment target */ while ( (NULL != wm) && ( (! wm->active) || - ( (NULL != oc->init.payment_target) && - (0 != strcasecmp (oc->init.payment_target, + ( (NULL != oc->parse_request.payment_target) && + (0 != strcasecmp (oc->parse_request.payment_target, wm->wire_method) ) ) ) ) wm = wm->next; if (NULL == wm) @@ -1888,7 +1876,7 @@ add_payment_details (struct OrderContext *oc) reply_with_error (oc, MHD_HTTP_NOT_FOUND, TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE, - oc->init.payment_target); + oc->parse_request.payment_target); return; } oc->add_payment_details.wm = wm; @@ -1907,37 +1895,21 @@ static void merge_inventory (struct OrderContext *oc) { /** - * inventory_products => instructions to add products to contract terms - * order.products => contains products that are not from the backend-managed inventory. + * parse_request.inventory_products => instructions to add products to contract terms + * parse_order.products => contains products that are not from the backend-managed inventory. */ - { - oc->merge_inventory.products = json_object_get (oc->init.order, - "products"); - if (NULL == oc->merge_inventory.products) - { - oc->merge_inventory.products = json_array (); - } - else if (! TMH_products_array_valid (oc->merge_inventory.products)) - { - reply_with_error (oc, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "order.products"); - return; - } - } - + oc->merge_inventory.products = json_deep_copy(oc->parse_order.products); /* Populate products from inventory product array and database */ { GNUNET_assert (NULL != oc->merge_inventory.products); - for (unsigned int i = 0; iinit.inventory_products_length; i++) + for (unsigned int i = 0; iparse_request.inventory_products_length; i++) { struct TALER_MERCHANTDB_ProductDetails pd; enum GNUNET_DB_QueryStatus qs; qs = TMH_db->lookup_product (TMH_db->cls, oc->hc->instance->settings.id, - oc->init.inventory_products[i].product_id, + oc->parse_request.inventory_products[i].product_id, &pd); if (qs <= 0) { @@ -1959,7 +1931,7 @@ merge_inventory (struct OrderContext *oc) case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Product %s from order unknown\n", - oc->init.inventory_products[i].product_id); + oc->parse_request.inventory_products[i].product_id); http_status = MHD_HTTP_NOT_FOUND; ec = TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN; break; @@ -1971,7 +1943,7 @@ merge_inventory (struct OrderContext *oc) reply_with_error (oc, http_status, ec, - oc->init.inventory_products[i].product_id); + oc->parse_request.inventory_products[i].product_id); return; } { @@ -1992,7 +1964,7 @@ merge_inventory (struct OrderContext *oc) pd.image), GNUNET_JSON_pack_uint64 ( "quantity", - oc->init.inventory_products[i].quantity)); + oc->parse_request.inventory_products[i].quantity)); GNUNET_assert (NULL != p); GNUNET_assert (0 == json_array_append_new (oc->merge_inventory.products, @@ -2009,27 +1981,29 @@ merge_inventory (struct OrderContext *oc) /** - * Parse the basics of the client request. + * Parse the client request. Upon success, + * continue processing by calling parse_order(). * * @param[in,out] oc order context to process */ static void -parse_order_request (struct OrderContext *oc) +parse_request (struct OrderContext *oc) { + // TODO: Set default values for optional fields in oc->parse_request const json_t *ip = NULL; const json_t *uuid = NULL; const char *otp_id = NULL; bool create_token = true; /* default */ struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_json ("order", - &oc->init.order), + &oc->parse_request.order), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_relative_time ("refund_delay", - &oc->init.refund_delay), + &oc->parse_request.refund_delay), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("payment_target", - &oc->init.payment_target), + &oc->parse_request.payment_target), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_array_const ("inventory_products", @@ -2063,7 +2037,7 @@ parse_order_request (struct OrderContext *oc) } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Refund delay is %s\n", - GNUNET_TIME_relative2s (oc->init.refund_delay, + GNUNET_TIME_relative2s (oc->parse_request.refund_delay, false)); TMH_db->expire_locks (TMH_db->cls); if (NULL != otp_id) @@ -2100,14 +2074,14 @@ parse_order_request (struct OrderContext *oc) case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: break; } - oc->init.pos_key = td.otp_key; - oc->init.pos_algorithm = td.otp_algorithm; + oc->parse_request.pos_key = td.otp_key; + oc->parse_request.pos_algorithm = td.otp_algorithm; } if (create_token) { GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, - &oc->init.claim_token, - sizeof (oc->init.claim_token)); + &oc->parse_request.claim_token, + sizeof (oc->parse_request.claim_token)); } /* Compute h_post_data (for idempotency check) */ { @@ -2130,19 +2104,19 @@ parse_order_request (struct OrderContext *oc) } GNUNET_CRYPTO_hash (req_body_enc, strlen (req_body_enc), - &oc->init.h_post_data.hash); + &oc->parse_request.h_post_data.hash); GNUNET_free (req_body_enc); } /* parse the inventory_products (optionally given) */ if (NULL != ip) { - GNUNET_array_grow (oc->init.inventory_products, - oc->init.inventory_products_length, + GNUNET_array_grow (oc->parse_request.inventory_products, + oc->parse_request.inventory_products_length, json_array_size (ip)); - for (unsigned int i = 0; iinit.inventory_products_length; i++) + for (unsigned int i = 0; iparse_request.inventory_products_length; i++) { - struct InventoryProduct *ipr = &oc->init.inventory_products[i]; + struct InventoryProduct *ipr = &oc->parse_request.inventory_products[i]; const char *error_name; unsigned int error_line; struct GNUNET_JSON_Specification ispec[] = { @@ -2178,10 +2152,10 @@ parse_order_request (struct OrderContext *oc) /* parse the lock_uuids (optionally given) */ if (NULL != uuid) { - GNUNET_array_grow (oc->init.uuids, - oc->init.uuids_length, + GNUNET_array_grow (oc->parse_request.uuids, + oc->parse_request.uuids_length, json_array_size (uuid)); - for (unsigned int i = 0; iinit.uuids_length; i++) + for (unsigned int i = 0; iparse_request.uuids_length; i++) { json_t *ui = json_array_get (uuid, i); @@ -2199,7 +2173,7 @@ parse_order_request (struct OrderContext *oc) return; } TMH_uuid_from_string (json_string_value (ui), - &oc->init.uuids[i]); + &oc->parse_request.uuids[i]); } } oc->phase++; @@ -2229,8 +2203,11 @@ TMH_private_post_orders ( oc->phase); switch (oc->phase) { - case ORDER_PHASE_INIT: - parse_order_request (oc); + case ORDER_PHASE_PARSE_REQUEST: + parse_request (oc); + break; + case ORDER_PHASE_PARSE_ORDER: + parse_order (oc); break; case ORDER_PHASE_MERGE_INVENTORY: merge_inventory (oc); @@ -2238,9 +2215,6 @@ TMH_private_post_orders ( case ORDER_PHASE_ADD_PAYMENT_DETAILS: add_payment_details (oc); break; - case ORDER_PHASE_PATCH_ORDER: - patch_order (oc); - break; case ORDER_PHASE_SET_EXCHANGES: if (set_exchanges (oc)) return MHD_YES; -- cgit v1.2.3