/*
  This file is part of TALER
  Copyright (C) 2014--2020 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
  Foundation; either version 3, or (at your option) any later version.
  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
  You should have received a copy of the GNU Affero General Public License along with
  TALER; see the file COPYING.  If not, see 
*/
/**
 * @file mhd_parsing.c
 * @brief functions to parse incoming requests (MHD arguments and JSON snippets)
 * @author Florian Dold
 * @author Benedikt Mueller
 * @author Christian Grothoff
 */
#include "platform.h"
#include 
#include 
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
enum GNUNET_GenericReturnValue
TALER_MHD_parse_post_json (struct MHD_Connection *connection,
                           void **con_cls,
                           const char *upload_data,
                           size_t *upload_data_size,
                           json_t **json)
{
  enum GNUNET_JSON_PostResult pr;
  pr = GNUNET_JSON_post_parser (TALER_MHD_REQUEST_BUFFER_MAX,
                                connection,
                                con_cls,
                                upload_data,
                                upload_data_size,
                                json);
  switch (pr)
  {
  case GNUNET_JSON_PR_OUT_OF_MEMORY:
    GNUNET_break (NULL == *json);
    return (MHD_NO ==
            TALER_MHD_reply_with_error (
              connection,
              MHD_HTTP_INTERNAL_SERVER_ERROR,
              TALER_EC_GENERIC_PARSER_OUT_OF_MEMORY,
              NULL)) ? GNUNET_SYSERR : GNUNET_NO;
  case GNUNET_JSON_PR_CONTINUE:
    GNUNET_break (NULL == *json);
    return GNUNET_YES;
  case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
    GNUNET_break (NULL == *json);
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                "Closing connection, upload too large\n");
    return MHD_NO;
  case GNUNET_JSON_PR_JSON_INVALID:
    GNUNET_break (NULL == *json);
    return (MHD_YES ==
            TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_BAD_REQUEST,
                                        TALER_EC_GENERIC_JSON_INVALID,
                                        NULL))
           ? GNUNET_NO : GNUNET_SYSERR;
  case GNUNET_JSON_PR_SUCCESS:
    GNUNET_break (NULL != *json);
    return GNUNET_YES;
  }
  /* this should never happen */
  GNUNET_break (0);
  return GNUNET_SYSERR;
}
void
TALER_MHD_parse_post_cleanup_callback (void *con_cls)
{
  GNUNET_JSON_post_parser_cleanup (con_cls);
}
enum GNUNET_GenericReturnValue
TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
                                  const char *param_name,
                                  void *out_data,
                                  size_t out_size)
{
  const char *str;
  str = MHD_lookup_connection_value (connection,
                                     MHD_GET_ARGUMENT_KIND,
                                     param_name);
  if (NULL == str)
  {
    return (MHD_NO ==
            TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_BAD_REQUEST,
                                        TALER_EC_GENERIC_PARAMETER_MISSING,
                                        param_name))
           ? GNUNET_SYSERR : GNUNET_NO;
  }
  if (GNUNET_OK !=
      GNUNET_STRINGS_string_to_data (str,
                                     strlen (str),
                                     out_data,
                                     out_size))
    return (MHD_NO ==
            TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_BAD_REQUEST,
                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
                                        param_name))
           ? GNUNET_SYSERR : GNUNET_NO;
  return GNUNET_OK;
}
enum GNUNET_GenericReturnValue
TALER_MHD_parse_json_data (struct MHD_Connection *connection,
                           const json_t *root,
                           struct GNUNET_JSON_Specification *spec)
{
  enum GNUNET_GenericReturnValue ret;
  const char *error_json_name;
  unsigned int error_line;
  ret = GNUNET_JSON_parse (root,
                           spec,
                           &error_json_name,
                           &error_line);
  if (GNUNET_SYSERR == ret)
  {
    if (NULL == error_json_name)
      error_json_name = "";
    ret = (MHD_YES ==
           TALER_MHD_REPLY_JSON_PACK (
             connection,
             MHD_HTTP_BAD_REQUEST,
             GNUNET_JSON_pack_string ("hint",
                                      TALER_ErrorCode_get_hint (
                                        TALER_EC_GENERIC_JSON_INVALID)),
             GNUNET_JSON_pack_uint64 ("code",
                                      TALER_EC_GENERIC_JSON_INVALID),
             GNUNET_JSON_pack_string ("field",
                                      error_json_name),
             GNUNET_JSON_pack_uint64 ("line",
                                      error_line)))
          ? GNUNET_NO : GNUNET_SYSERR;
    return ret;
  }
  return GNUNET_YES;
}
enum GNUNET_GenericReturnValue
TALER_MHD_parse_internal_json_data (struct MHD_Connection *connection,
                                    const json_t *root,
                                    struct GNUNET_JSON_Specification *spec)
{
  enum GNUNET_GenericReturnValue ret;
  const char *error_json_name;
  unsigned int error_line;
  ret = GNUNET_JSON_parse (root,
                           spec,
                           &error_json_name,
                           &error_line);
  if (GNUNET_SYSERR == ret)
  {
    if (NULL == error_json_name)
      error_json_name = "";
    ret = (MHD_YES ==
           TALER_MHD_REPLY_JSON_PACK (
             connection,
             MHD_HTTP_INTERNAL_SERVER_ERROR,
             GNUNET_JSON_pack_string ("hint",
                                      TALER_ErrorCode_get_hint (
                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)),
             GNUNET_JSON_pack_uint64 ("code",
                                      TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE),
             GNUNET_JSON_pack_string ("field",
                                      error_json_name),
             GNUNET_JSON_pack_uint64 ("line",
                                      error_line)))
          ? GNUNET_NO : GNUNET_SYSERR;
    return ret;
  }
  return GNUNET_YES;
}
enum GNUNET_GenericReturnValue
TALER_MHD_parse_json_array (struct MHD_Connection *connection,
                            const json_t *root,
                            struct GNUNET_JSON_Specification *spec,
                            ...)
{
  enum GNUNET_GenericReturnValue ret;
  const char *error_json_name;
  unsigned int error_line;
  va_list ap;
  json_int_t dim;
  va_start (ap, spec);
  dim = 0;
  while ( (-1 != (ret = va_arg (ap, int))) &&
          (NULL != root) )
  {
    dim++;
    root = json_array_get (root, ret);
  }
  va_end (ap);
  if (NULL == root)
  {
    ret = (MHD_YES ==
           TALER_MHD_REPLY_JSON_PACK (
             connection,
             MHD_HTTP_BAD_REQUEST,
             GNUNET_JSON_pack_string ("hint",
                                      TALER_ErrorCode_get_hint (
                                        TALER_EC_GENERIC_JSON_INVALID)),
             GNUNET_JSON_pack_uint64 ("code",
                                      TALER_EC_GENERIC_JSON_INVALID),
             GNUNET_JSON_pack_string ("detail",
                                      "expected array"),
             GNUNET_JSON_pack_uint64 ("dimension",
                                      dim)))
          ? GNUNET_NO : GNUNET_SYSERR;
    return ret;
  }
  ret = GNUNET_JSON_parse (root,
                           spec,
                           &error_json_name,
                           &error_line);
  if (GNUNET_SYSERR == ret)
  {
    if (NULL == error_json_name)
      error_json_name = "";
    ret = (MHD_YES ==
           TALER_MHD_REPLY_JSON_PACK (
             connection,
             MHD_HTTP_BAD_REQUEST,
             GNUNET_JSON_pack_string ("detail",
                                      error_json_name),
             GNUNET_JSON_pack_string ("hint",
                                      TALER_ErrorCode_get_hint (
                                        TALER_EC_GENERIC_JSON_INVALID)),
             GNUNET_JSON_pack_uint64 ("code",
                                      TALER_EC_GENERIC_JSON_INVALID),
             GNUNET_JSON_pack_uint64 ("line",
                                      error_line)))
          ? GNUNET_NO : GNUNET_SYSERR;
    return ret;
  }
  return GNUNET_YES;
}
/* end of mhd_parsing.c */