2015-01-16 13:50:07 +01:00
|
|
|
/*
|
|
|
|
This file is part of TALER
|
2015-02-08 00:16:22 +01:00
|
|
|
Copyright (C) 2014 GNUnet e.V.
|
2015-01-16 13:50:07 +01:00
|
|
|
|
|
|
|
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, If not, see <http://www.gnu.org/licenses/>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file taler-mint-httpd_parsing.c
|
|
|
|
* @brief functions to parse incoming requests (MHD arguments and JSON snippets)
|
|
|
|
* @author Florian Dold
|
|
|
|
* @author Benedikt Mueller
|
|
|
|
* @author Christian Grothoff
|
|
|
|
*/
|
|
|
|
|
2015-01-08 18:37:20 +01:00
|
|
|
#include "platform.h"
|
|
|
|
#include <gnunet/gnunet_util_lib.h>
|
2015-01-16 13:50:07 +01:00
|
|
|
#include "taler-mint-httpd_parsing.h"
|
|
|
|
#include "taler-mint-httpd_responses.h"
|
2015-01-08 18:37:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initial size for POST
|
|
|
|
* request buffer.
|
|
|
|
*/
|
|
|
|
#define REQUEST_BUFFER_INITIAL 1024
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Maximum POST request size
|
|
|
|
*/
|
|
|
|
#define REQUEST_BUFFER_MAX (1024*1024)
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Buffer for POST requests.
|
|
|
|
*/
|
|
|
|
struct Buffer
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Allocated memory
|
|
|
|
*/
|
|
|
|
char *data;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Number of valid bytes in buffer.
|
|
|
|
*/
|
|
|
|
size_t fill;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Number of allocated bytes in buffer.
|
|
|
|
*/
|
|
|
|
size_t alloc;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize a buffer.
|
|
|
|
*
|
|
|
|
* @param buf the buffer to initialize
|
|
|
|
* @param data the initial data
|
|
|
|
* @param data_size size of the initial data
|
|
|
|
* @param alloc_size size of the buffer
|
|
|
|
* @param max_size maximum size that the buffer can grow to
|
|
|
|
* @return a GNUnet result code
|
|
|
|
*/
|
|
|
|
static int
|
2015-01-16 13:50:07 +01:00
|
|
|
buffer_init (struct Buffer *buf,
|
|
|
|
const void *data,
|
|
|
|
size_t data_size,
|
|
|
|
size_t alloc_size,
|
|
|
|
size_t max_size)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
|
|
|
if (data_size > max_size || alloc_size > max_size)
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
if (data_size > alloc_size)
|
|
|
|
alloc_size = data_size;
|
|
|
|
buf->data = GNUNET_malloc (alloc_size);
|
|
|
|
memcpy (buf->data, data, data_size);
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free the data in a buffer. Does *not* free
|
|
|
|
* the buffer object itself.
|
|
|
|
*
|
|
|
|
* @param buf buffer to de-initialize
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
buffer_deinit (struct Buffer *buf)
|
|
|
|
{
|
|
|
|
GNUNET_free (buf->data);
|
|
|
|
buf->data = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Append data to a buffer, growing the buffer if necessary.
|
|
|
|
*
|
|
|
|
* @param buf the buffer to append to
|
|
|
|
* @param data the data to append
|
2015-03-28 15:42:07 +01:00
|
|
|
* @param data_size the size of @a data
|
2015-01-08 18:37:20 +01:00
|
|
|
* @param max_size maximum size that the buffer can grow to
|
2015-01-28 14:55:25 +01:00
|
|
|
* @return #GNUNET_OK on success,
|
|
|
|
* #GNUNET_NO if the buffer can't accomodate for the new data
|
2015-01-08 18:37:20 +01:00
|
|
|
*/
|
|
|
|
static int
|
2015-01-16 13:50:07 +01:00
|
|
|
buffer_append (struct Buffer *buf,
|
|
|
|
const void *data,
|
|
|
|
size_t data_size,
|
|
|
|
size_t max_size)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
|
|
|
if (buf->fill + data_size > max_size)
|
|
|
|
return GNUNET_NO;
|
|
|
|
if (data_size + buf->fill > buf->alloc)
|
|
|
|
{
|
|
|
|
char *new_buf;
|
|
|
|
size_t new_size = buf->alloc;
|
|
|
|
while (new_size < buf->fill + data_size)
|
|
|
|
new_size += 2;
|
|
|
|
if (new_size > max_size)
|
|
|
|
return GNUNET_NO;
|
|
|
|
new_buf = GNUNET_malloc (new_size);
|
|
|
|
memcpy (new_buf, buf->data, buf->fill);
|
|
|
|
buf->data = new_buf;
|
|
|
|
buf->alloc = new_size;
|
|
|
|
}
|
|
|
|
memcpy (buf->data + buf->fill, data, data_size);
|
|
|
|
buf->fill += data_size;
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-03-28 15:42:07 +01:00
|
|
|
* Process a POST request containing a JSON object. This function
|
|
|
|
* realizes an MHD POST processor that will (incrementally) process
|
|
|
|
* JSON data uploaded to the HTTP server. It will store the required
|
|
|
|
* state in the @a con_cls, which must be cleaned up using
|
2015-03-27 19:58:40 +01:00
|
|
|
* #TMH_PARSE_post_cleanup_callback().
|
2015-01-08 18:37:20 +01:00
|
|
|
*
|
|
|
|
* @param connection the MHD connection
|
2015-03-28 15:42:07 +01:00
|
|
|
* @param con_cls the closure (points to a `struct Buffer *`)
|
2015-01-08 18:37:20 +01:00
|
|
|
* @param upload_data the POST data
|
2015-01-16 14:27:42 +01:00
|
|
|
* @param upload_data_size number of bytes in @a upload_data
|
2015-01-08 18:37:20 +01:00
|
|
|
* @param json the JSON object for a completed request
|
2015-01-28 14:55:25 +01:00
|
|
|
* @return
|
|
|
|
* #GNUNET_YES if json object was parsed or at least
|
2015-01-16 14:27:42 +01:00
|
|
|
* may be parsed in the future (call again);
|
|
|
|
* `*json` will be NULL if we need to be called again,
|
|
|
|
* and non-NULL if we are done.
|
2015-01-28 14:55:25 +01:00
|
|
|
* #GNUNET_NO is request incomplete or invalid
|
2015-01-16 14:27:42 +01:00
|
|
|
* (error message was generated)
|
2015-01-28 14:55:25 +01:00
|
|
|
* #GNUNET_SYSERR on internal error
|
2015-01-16 14:27:42 +01:00
|
|
|
* (we could not even queue an error message,
|
|
|
|
* close HTTP session with MHD_NO)
|
2015-01-08 18:37:20 +01:00
|
|
|
*/
|
|
|
|
int
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_post_json (struct MHD_Connection *connection,
|
2015-03-28 15:42:07 +01:00
|
|
|
void **con_cls,
|
|
|
|
const char *upload_data,
|
|
|
|
size_t *upload_data_size,
|
|
|
|
json_t **json)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
|
|
|
struct Buffer *r = *con_cls;
|
|
|
|
|
2015-01-16 14:27:42 +01:00
|
|
|
*json = NULL;
|
2015-01-08 18:37:20 +01:00
|
|
|
if (NULL == *con_cls)
|
|
|
|
{
|
|
|
|
/* We are seeing a fresh POST request. */
|
|
|
|
r = GNUNET_new (struct Buffer);
|
2015-01-16 13:50:07 +01:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
buffer_init (r,
|
|
|
|
upload_data,
|
|
|
|
*upload_data_size,
|
|
|
|
REQUEST_BUFFER_INITIAL,
|
|
|
|
REQUEST_BUFFER_MAX))
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
|
|
|
*con_cls = NULL;
|
|
|
|
buffer_deinit (r);
|
|
|
|
GNUNET_free (r);
|
2015-01-16 14:27:42 +01:00
|
|
|
return (MHD_NO ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_internal_error (connection,
|
2015-03-29 14:17:52 +02:00
|
|
|
"out of memory"))
|
2015-01-16 14:27:42 +01:00
|
|
|
? GNUNET_SYSERR : GNUNET_NO;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2015-01-16 14:27:42 +01:00
|
|
|
/* everything OK, wait for more POST data */
|
2015-01-08 18:37:20 +01:00
|
|
|
*upload_data_size = 0;
|
|
|
|
*con_cls = r;
|
2015-01-16 14:27:42 +01:00
|
|
|
return GNUNET_YES;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
|
|
|
if (0 != *upload_data_size)
|
|
|
|
{
|
|
|
|
/* We are seeing an old request with more data available. */
|
|
|
|
|
2015-01-16 13:50:07 +01:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
buffer_append (r,
|
|
|
|
upload_data,
|
|
|
|
*upload_data_size,
|
|
|
|
REQUEST_BUFFER_MAX))
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-01-16 14:27:42 +01:00
|
|
|
/* Request too long */
|
2015-01-08 18:37:20 +01:00
|
|
|
*con_cls = NULL;
|
|
|
|
buffer_deinit (r);
|
|
|
|
GNUNET_free (r);
|
2015-01-16 14:27:42 +01:00
|
|
|
return (MHD_NO ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_request_too_large (connection))
|
2015-01-16 14:27:42 +01:00
|
|
|
? GNUNET_SYSERR : GNUNET_NO;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2015-01-16 14:27:42 +01:00
|
|
|
/* everything OK, wait for more POST data */
|
2015-01-08 18:37:20 +01:00
|
|
|
*upload_data_size = 0;
|
2015-01-16 14:27:42 +01:00
|
|
|
return GNUNET_YES;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We have seen the whole request. */
|
|
|
|
|
2015-01-16 14:27:42 +01:00
|
|
|
*json = json_loadb (r->data,
|
|
|
|
r->fill,
|
|
|
|
0,
|
|
|
|
NULL);
|
2015-01-08 18:37:20 +01:00
|
|
|
buffer_deinit (r);
|
|
|
|
GNUNET_free (r);
|
|
|
|
if (NULL == *json)
|
|
|
|
{
|
2015-01-16 13:50:07 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
2015-01-16 14:27:42 +01:00
|
|
|
"Failed to parse JSON request body\n");
|
2015-01-16 13:50:07 +01:00
|
|
|
return (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_invalid_json (connection))
|
2015-01-16 13:50:07 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
|
|
|
*con_cls = NULL;
|
|
|
|
|
|
|
|
return GNUNET_YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-16 14:04:02 +01:00
|
|
|
/**
|
|
|
|
* Function called whenever we are done with a request
|
|
|
|
* to clean up our state.
|
|
|
|
*
|
|
|
|
* @param con_cls value as it was left by
|
2015-03-27 19:58:40 +01:00
|
|
|
* #TMH_PARSE_post_json(), to be cleaned up
|
2015-01-16 14:04:02 +01:00
|
|
|
*/
|
|
|
|
void
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_post_cleanup_callback (void *con_cls)
|
2015-01-16 14:04:02 +01:00
|
|
|
{
|
|
|
|
struct Buffer *r = con_cls;
|
|
|
|
|
|
|
|
if (NULL != r)
|
|
|
|
buffer_deinit (r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-29 15:45:05 +01:00
|
|
|
/**
|
|
|
|
* Extract base32crockford encoded data from request.
|
|
|
|
*
|
|
|
|
* Queues an error response to the connection if the parameter is missing or
|
|
|
|
* invalid.
|
|
|
|
*
|
|
|
|
* @param connection the MHD connection
|
|
|
|
* @param param_name the name of the parameter with the key
|
|
|
|
* @param[out] out_data pointer to store the result
|
|
|
|
* @param out_size expected size of data
|
|
|
|
* @return
|
|
|
|
* #GNUNET_YES if the the argument is present
|
|
|
|
* #GNUNET_NO if the argument is absent or malformed
|
|
|
|
* #GNUNET_SYSERR on internal error (error response could not be sent)
|
|
|
|
*/
|
|
|
|
int
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
|
2015-04-08 22:28:52 +02:00
|
|
|
const char *param_name,
|
|
|
|
void *out_data,
|
|
|
|
size_t out_size)
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
str = MHD_lookup_connection_value (connection,
|
|
|
|
MHD_GET_ARGUMENT_KIND,
|
|
|
|
param_name);
|
|
|
|
if (NULL == str)
|
|
|
|
{
|
|
|
|
return (MHD_NO ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_arg_missing (connection, param_name))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_SYSERR : GNUNET_NO;
|
|
|
|
}
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
GNUNET_STRINGS_string_to_data (str,
|
|
|
|
strlen (str),
|
|
|
|
out_data,
|
|
|
|
out_size))
|
|
|
|
return (MHD_NO ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_arg_invalid (connection, param_name))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_SYSERR : GNUNET_NO;
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extraxt variable-size base32crockford encoded data from request.
|
|
|
|
*
|
|
|
|
* Queues an error response to the connection if the parameter is missing
|
|
|
|
* or the encoding is invalid.
|
|
|
|
*
|
|
|
|
* @param connection the MHD connection
|
|
|
|
* @param param_name the name of the parameter with the key
|
|
|
|
* @param[out] out_data pointer to allocate buffer and store the result
|
|
|
|
* @param[out] out_size set to the size of the buffer allocated in @a out_data
|
|
|
|
* @return
|
|
|
|
* #GNUNET_YES if the the argument is present
|
|
|
|
* #GNUNET_NO if the argument is absent or malformed
|
|
|
|
* #GNUNET_SYSERR on internal error (error response could not be sent)
|
|
|
|
*/
|
|
|
|
int
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
const char *param_name,
|
|
|
|
void **out_data,
|
|
|
|
size_t *out_size)
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
size_t slen;
|
|
|
|
size_t olen;
|
|
|
|
void *out;
|
|
|
|
|
|
|
|
str = MHD_lookup_connection_value (connection,
|
|
|
|
MHD_GET_ARGUMENT_KIND,
|
|
|
|
param_name);
|
|
|
|
if (NULL == str)
|
|
|
|
{
|
|
|
|
return (MHD_NO ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_arg_missing (connection, param_name))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_SYSERR : GNUNET_NO;
|
|
|
|
}
|
|
|
|
slen = strlen (str);
|
|
|
|
olen = (slen * 5) / 8;
|
|
|
|
out = GNUNET_malloc (olen);
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
GNUNET_STRINGS_string_to_data (str,
|
|
|
|
strlen (str),
|
|
|
|
out,
|
|
|
|
olen))
|
|
|
|
{
|
|
|
|
GNUNET_free (out);
|
|
|
|
*out_size = 0;
|
|
|
|
return (MHD_NO ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_arg_invalid (connection, param_name))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_SYSERR : GNUNET_NO;
|
|
|
|
}
|
|
|
|
*out_data = out;
|
|
|
|
*out_size = olen;
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-08 18:37:20 +01:00
|
|
|
/**
|
|
|
|
* Navigate through a JSON tree.
|
|
|
|
*
|
|
|
|
* Sends an error response if navigation is impossible (i.e.
|
|
|
|
* the JSON object is invalid)
|
|
|
|
*
|
|
|
|
* @param connection the connection to send an error response to
|
|
|
|
* @param root the JSON node to start the navigation at.
|
2015-03-27 19:58:40 +01:00
|
|
|
* @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`)
|
2015-01-19 21:04:58 +01:00
|
|
|
* @return
|
|
|
|
* #GNUNET_YES if navigation was successful
|
|
|
|
* #GNUNET_NO if json is malformed, error response was generated
|
|
|
|
* #GNUNET_SYSERR on internal error (no response was generated,
|
2015-01-16 15:04:47 +01:00
|
|
|
* connection must be closed)
|
2015-01-08 18:37:20 +01:00
|
|
|
*/
|
|
|
|
int
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
2015-03-29 14:17:52 +02:00
|
|
|
const json_t *root,
|
|
|
|
...)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
|
|
|
va_list argp;
|
2015-01-16 15:04:47 +01:00
|
|
|
int ret;
|
|
|
|
json_t *path; /* what's our current path from 'root'? */
|
2015-01-08 18:37:20 +01:00
|
|
|
|
|
|
|
path = json_array ();
|
2015-01-16 15:04:47 +01:00
|
|
|
va_start (argp, root);
|
2015-01-16 15:07:53 +01:00
|
|
|
ret = 2; /* just not any of the valid return values */
|
2015-01-16 15:04:47 +01:00
|
|
|
while (2 == ret)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-03-27 19:58:40 +01:00
|
|
|
enum TMH_PARSE_JsonNavigationCommand command
|
2015-01-16 15:04:47 +01:00
|
|
|
= va_arg (argp,
|
2015-03-27 19:58:40 +01:00
|
|
|
enum TMH_PARSE_JsonNavigationCommand);
|
2015-01-16 15:04:47 +01:00
|
|
|
|
2015-01-08 18:37:20 +01:00
|
|
|
switch (command)
|
|
|
|
{
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_FIELD:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
const char *fname = va_arg(argp, const char *);
|
|
|
|
|
|
|
|
json_array_append_new (path,
|
|
|
|
json_string (fname));
|
|
|
|
root = json_object_get (root,
|
|
|
|
fname);
|
|
|
|
if (NULL == root)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-01-29 15:45:05 +01:00
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-04-08 22:28:52 +02:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:s, s:o}",
|
|
|
|
"error", "missing field in JSON",
|
|
|
|
"field", fname,
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2015-01-16 15:04:47 +01:00
|
|
|
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_INDEX:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
int fnum = va_arg(argp, int);
|
|
|
|
|
|
|
|
json_array_append_new (path,
|
|
|
|
json_integer (fnum));
|
|
|
|
root = json_array_get (root,
|
|
|
|
fnum);
|
|
|
|
if (NULL == root)
|
|
|
|
{
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-04-08 22:28:52 +02:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
|
|
|
"error", "missing index in JSON",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2015-01-29 15:45:05 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_DATA:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
void *where = va_arg (argp, void *);
|
|
|
|
size_t len = va_arg (argp, size_t);
|
|
|
|
const char *str;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
// FIXME: avoidable code duplication here...
|
|
|
|
str = json_string_value (root);
|
|
|
|
if (NULL == str)
|
|
|
|
{
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-01-29 15:45:05 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
2015-04-08 22:28:52 +02:00
|
|
|
"error", "string expected",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
res = GNUNET_STRINGS_string_to_data (str, strlen (str),
|
|
|
|
where, len);
|
|
|
|
if (GNUNET_OK != res)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-01-29 15:45:05 +01:00
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-04-08 22:28:52 +02:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
|
|
|
"error", "malformed binary data in JSON",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = GNUNET_OK;
|
|
|
|
}
|
|
|
|
break;
|
2015-01-16 15:04:47 +01:00
|
|
|
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_DATA_VAR:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
void **where = va_arg (argp, void **);
|
|
|
|
size_t *len = va_arg (argp, size_t *);
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
// FIXME: avoidable code duplication here...
|
|
|
|
str = json_string_value (root);
|
|
|
|
if (NULL == str)
|
|
|
|
{
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_internal_error (connection,
|
2015-01-29 15:45:05 +01:00
|
|
|
"json_string_value() failed"))
|
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2015-01-29 15:45:05 +01:00
|
|
|
*len = (strlen (str) * 5) / 8;
|
|
|
|
if (NULL != where)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
2015-01-29 15:45:05 +01:00
|
|
|
*where = GNUNET_malloc (*len);
|
|
|
|
res = GNUNET_STRINGS_string_to_data (str,
|
|
|
|
strlen (str),
|
|
|
|
*where,
|
|
|
|
*len);
|
2015-01-08 18:37:20 +01:00
|
|
|
if (GNUNET_OK != res)
|
|
|
|
{
|
2015-01-29 15:45:05 +01:00
|
|
|
GNUNET_free (*where);
|
|
|
|
*where = NULL;
|
|
|
|
*len = 0;
|
2015-01-16 15:04:47 +01:00
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-04-08 22:28:52 +02:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
|
|
|
"error", "malformed binary data in JSON",
|
|
|
|
"path", path))
|
2015-01-16 15:04:47 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-29 15:45:05 +01:00
|
|
|
ret = GNUNET_OK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_TYPED_JSON:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
int typ = va_arg (argp, int);
|
|
|
|
const json_t **r_json = va_arg (argp, const json_t **);
|
|
|
|
|
|
|
|
if ( (-1 != typ) && (json_typeof (root) != typ))
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-01-29 15:45:05 +01:00
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-04-08 22:28:52 +02:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:i, s:i, s:o}",
|
|
|
|
"error", "wrong JSON field type",
|
|
|
|
"type_expected", typ,
|
|
|
|
"type_actual", json_typeof (root),
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*r_json = root;
|
|
|
|
ret = GNUNET_OK;
|
|
|
|
}
|
|
|
|
break;
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
2015-03-29 14:17:52 +02:00
|
|
|
struct TALER_DenominationPublicKey *where;
|
2015-01-29 15:45:05 +01:00
|
|
|
size_t len;
|
|
|
|
const char *str;
|
|
|
|
int res;
|
|
|
|
void *buf;
|
|
|
|
|
2015-03-29 14:17:52 +02:00
|
|
|
where = va_arg (argp,
|
|
|
|
struct TALER_DenominationPublicKey *);
|
2015-01-29 15:45:05 +01:00
|
|
|
str = json_string_value (root);
|
|
|
|
if (NULL == str)
|
|
|
|
{
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
2015-04-08 22:28:52 +02:00
|
|
|
"error", "string expected",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2015-01-29 15:45:05 +01:00
|
|
|
len = (strlen (str) * 5) / 8;
|
|
|
|
buf = GNUNET_malloc (len);
|
|
|
|
res = GNUNET_STRINGS_string_to_data (str,
|
|
|
|
strlen (str),
|
|
|
|
buf,
|
|
|
|
len);
|
|
|
|
if (GNUNET_OK != res)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-01-29 15:45:05 +01:00
|
|
|
GNUNET_free (buf);
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
2015-04-08 22:28:52 +02:00
|
|
|
"error", "malformed binary data in JSON",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2015-03-29 14:17:52 +02:00
|
|
|
where->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf,
|
|
|
|
len);
|
2015-01-29 15:45:05 +01:00
|
|
|
GNUNET_free (buf);
|
2015-03-29 14:17:52 +02:00
|
|
|
if (NULL == where->rsa_public_key)
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
2015-04-08 22:28:52 +02:00
|
|
|
"error", "malformed RSA public key in JSON",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = GNUNET_OK;
|
2015-01-08 18:37:20 +01:00
|
|
|
break;
|
2015-01-29 15:45:05 +01:00
|
|
|
}
|
|
|
|
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
2015-03-29 14:17:52 +02:00
|
|
|
struct TALER_DenominationSignature *where;
|
2015-01-29 15:45:05 +01:00
|
|
|
size_t len;
|
|
|
|
const char *str;
|
|
|
|
int res;
|
|
|
|
void *buf;
|
|
|
|
|
2015-03-29 14:17:52 +02:00
|
|
|
where = va_arg (argp,
|
|
|
|
struct TALER_DenominationSignature *);
|
2015-01-29 15:45:05 +01:00
|
|
|
str = json_string_value (root);
|
|
|
|
if (NULL == str)
|
|
|
|
{
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
2015-04-08 22:28:52 +02:00
|
|
|
"error", "string expected",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
len = (strlen (str) * 5) / 8;
|
|
|
|
buf = GNUNET_malloc (len);
|
|
|
|
res = GNUNET_STRINGS_string_to_data (str,
|
|
|
|
strlen (str),
|
|
|
|
buf,
|
|
|
|
len);
|
|
|
|
if (GNUNET_OK != res)
|
|
|
|
{
|
|
|
|
GNUNET_free (buf);
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
2015-04-08 22:28:52 +02:00
|
|
|
"error", "malformed binary data in JSON",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
|
|
|
}
|
2015-03-29 14:17:52 +02:00
|
|
|
where->rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (buf,
|
|
|
|
len);
|
2015-01-29 15:45:05 +01:00
|
|
|
GNUNET_free (buf);
|
2015-03-29 14:17:52 +02:00
|
|
|
if (NULL == where->rsa_signature)
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:o}",
|
2015-04-08 22:28:52 +02:00
|
|
|
"error", "malformed RSA signature in JSON",
|
|
|
|
"path", path))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = GNUNET_OK;
|
2015-01-16 15:04:47 +01:00
|
|
|
break;
|
2015-01-29 15:45:05 +01:00
|
|
|
}
|
|
|
|
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_AMOUNT:
|
2015-03-22 17:10:45 +01:00
|
|
|
{
|
|
|
|
struct TALER_Amount *where = va_arg (argp, void *);
|
|
|
|
|
2015-03-27 19:58:40 +01:00
|
|
|
ret = TMH_PARSE_amount_json (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
(json_t *) root,
|
|
|
|
where);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
|
|
|
|
{
|
|
|
|
struct GNUNET_TIME_Absolute *where = va_arg (argp, void *);
|
2015-04-11 16:29:11 +02:00
|
|
|
|
2015-03-28 17:10:39 +01:00
|
|
|
ret = TMH_PARSE_time_abs_json (connection,
|
|
|
|
(json_t *) root,
|
|
|
|
where);
|
2015-03-22 17:10:45 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-01-29 15:45:05 +01:00
|
|
|
default:
|
|
|
|
GNUNET_break (0);
|
|
|
|
ret = (MHD_YES ==
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_internal_error (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
"unhandled value in switch"))
|
2015-01-29 15:45:05 +01:00
|
|
|
? GNUNET_NO : GNUNET_SYSERR;
|
|
|
|
break;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-16 15:04:47 +01:00
|
|
|
va_end (argp);
|
|
|
|
json_decref (path);
|
|
|
|
return ret;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-19 21:04:58 +01:00
|
|
|
/**
|
|
|
|
* Parse JSON object into components based on the given field
|
|
|
|
* specification.
|
|
|
|
*
|
|
|
|
* @param connection the connection to send an error response to
|
|
|
|
* @param root the JSON node to start the navigation at.
|
|
|
|
* @param spec field specification for the parser
|
|
|
|
* @return
|
|
|
|
* #GNUNET_YES if navigation was successful (caller is responsible
|
|
|
|
* for freeing allocated variable-size data using
|
2015-03-27 19:58:40 +01:00
|
|
|
* #TMH_PARSE_release_data() when done)
|
2015-01-19 21:04:58 +01:00
|
|
|
* #GNUNET_NO if json is malformed, error response was generated
|
|
|
|
* #GNUNET_SYSERR on internal error
|
|
|
|
*/
|
|
|
|
int
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_json_data (struct MHD_Connection *connection,
|
2015-01-19 21:04:58 +01:00
|
|
|
const json_t *root,
|
2015-03-27 19:58:40 +01:00
|
|
|
struct TMH_PARSE_FieldSpecification *spec)
|
2015-01-19 21:04:58 +01:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int ret;
|
2015-01-26 12:22:26 +01:00
|
|
|
void *ptr;
|
2015-01-19 21:04:58 +01:00
|
|
|
|
|
|
|
ret = GNUNET_YES;
|
|
|
|
for (i=0; NULL != spec[i].field_name; i++)
|
|
|
|
{
|
2015-03-22 17:10:45 +01:00
|
|
|
if (GNUNET_YES != ret)
|
|
|
|
break;
|
2015-01-29 15:06:55 +01:00
|
|
|
switch (spec[i].command)
|
2015-01-26 12:22:26 +01:00
|
|
|
{
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_FIELD:
|
2015-01-29 15:06:55 +01:00
|
|
|
GNUNET_break (0);
|
|
|
|
return GNUNET_SYSERR;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_INDEX:
|
2015-01-29 15:06:55 +01:00
|
|
|
GNUNET_break (0);
|
|
|
|
return GNUNET_SYSERR;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_DATA:
|
|
|
|
ret = TMH_PARSE_navigate_json (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
root,
|
|
|
|
TMH_PARSE_JNC_FIELD,
|
|
|
|
spec[i].field_name,
|
|
|
|
TMH_PARSE_JNC_RET_DATA,
|
|
|
|
spec[i].destination,
|
|
|
|
spec[i].destination_size_in);
|
2015-01-29 15:06:55 +01:00
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_DATA_VAR:
|
2015-01-26 12:22:26 +01:00
|
|
|
ptr = NULL;
|
2015-03-27 19:58:40 +01:00
|
|
|
ret = TMH_PARSE_navigate_json (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
root,
|
|
|
|
TMH_PARSE_JNC_FIELD,
|
|
|
|
spec[i].field_name,
|
|
|
|
TMH_PARSE_JNC_RET_DATA_VAR,
|
|
|
|
&ptr,
|
|
|
|
&spec[i].destination_size_out);
|
2015-01-26 12:22:26 +01:00
|
|
|
spec[i].destination = ptr;
|
2015-01-29 15:06:55 +01:00
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_TYPED_JSON:
|
2015-01-29 15:06:55 +01:00
|
|
|
ptr = NULL;
|
2015-03-27 19:58:40 +01:00
|
|
|
ret = TMH_PARSE_navigate_json (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
root,
|
|
|
|
TMH_PARSE_JNC_FIELD,
|
|
|
|
spec[i].field_name,
|
|
|
|
TMH_PARSE_JNC_RET_TYPED_JSON,
|
|
|
|
spec[i].type,
|
|
|
|
&ptr);
|
2015-01-29 15:45:05 +01:00
|
|
|
*((void**)spec[i].destination) = ptr;
|
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
|
2015-01-29 15:45:05 +01:00
|
|
|
ptr = NULL;
|
2015-03-27 19:58:40 +01:00
|
|
|
ret = TMH_PARSE_navigate_json (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
root,
|
|
|
|
TMH_PARSE_JNC_FIELD,
|
|
|
|
spec[i].field_name,
|
|
|
|
TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
|
|
|
|
&ptr);
|
2015-01-29 15:45:05 +01:00
|
|
|
spec[i].destination = ptr;
|
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
|
2015-01-29 15:45:05 +01:00
|
|
|
ptr = NULL;
|
2015-03-27 19:58:40 +01:00
|
|
|
ret = TMH_PARSE_navigate_json (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
root,
|
|
|
|
TMH_PARSE_JNC_FIELD,
|
|
|
|
spec[i].field_name,
|
|
|
|
TMH_PARSE_JNC_RET_RSA_SIGNATURE,
|
|
|
|
&ptr);
|
2015-01-29 15:06:55 +01:00
|
|
|
spec[i].destination = ptr;
|
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_AMOUNT:
|
2015-03-22 17:10:45 +01:00
|
|
|
GNUNET_assert (sizeof (struct TALER_Amount) ==
|
|
|
|
spec[i].destination_size_in);
|
2015-03-27 19:58:40 +01:00
|
|
|
ret = TMH_PARSE_navigate_json (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
root,
|
|
|
|
TMH_PARSE_JNC_FIELD,
|
|
|
|
spec[i].field_name,
|
|
|
|
TMH_PARSE_JNC_RET_AMOUNT,
|
|
|
|
&spec[i].destination);
|
|
|
|
break;
|
|
|
|
case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
|
|
|
|
GNUNET_assert (sizeof (struct GNUNET_TIME_Absolute) ==
|
|
|
|
spec[i].destination_size_in);
|
|
|
|
ret = TMH_PARSE_navigate_json (connection,
|
|
|
|
root,
|
|
|
|
TMH_PARSE_JNC_FIELD,
|
|
|
|
spec[i].field_name,
|
|
|
|
TMH_PARSE_JNC_RET_TIME_ABSOLUTE,
|
|
|
|
&spec[i].destination);
|
2015-03-22 17:10:45 +01:00
|
|
|
break;
|
2015-01-26 12:22:26 +01:00
|
|
|
}
|
2015-01-19 21:04:58 +01:00
|
|
|
}
|
|
|
|
if (GNUNET_YES != ret)
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_release_data (spec);
|
2015-01-19 21:04:58 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Release all memory allocated for the variable-size fields in
|
|
|
|
* the parser specification.
|
|
|
|
*
|
|
|
|
* @param spec specification to free
|
|
|
|
*/
|
|
|
|
void
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec)
|
2015-01-19 21:04:58 +01:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2015-01-29 15:45:05 +01:00
|
|
|
void *ptr;
|
2015-01-19 21:04:58 +01:00
|
|
|
|
|
|
|
for (i=0; NULL != spec[i].field_name; i++)
|
2015-01-29 15:06:55 +01:00
|
|
|
{
|
|
|
|
switch (spec[i].command)
|
2015-01-19 21:04:58 +01:00
|
|
|
{
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_FIELD:
|
2015-01-29 15:06:55 +01:00
|
|
|
GNUNET_break (0);
|
|
|
|
return;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_INDEX:
|
2015-01-29 15:06:55 +01:00
|
|
|
GNUNET_break (0);
|
|
|
|
return;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_DATA:
|
2015-01-29 15:06:55 +01:00
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_DATA_VAR:
|
2015-01-29 15:06:55 +01:00
|
|
|
if (0 != spec[i].destination_size_out)
|
|
|
|
{
|
|
|
|
GNUNET_free (spec[i].destination);
|
|
|
|
spec[i].destination = NULL;
|
|
|
|
spec[i].destination_size_out = 0;
|
|
|
|
}
|
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_TYPED_JSON:
|
2015-01-29 15:45:05 +01:00
|
|
|
ptr = *(void **) spec[i].destination;
|
|
|
|
if (NULL != ptr)
|
2015-01-29 15:06:55 +01:00
|
|
|
{
|
2015-01-29 15:45:05 +01:00
|
|
|
json_decref (ptr);
|
|
|
|
*(void**) spec[i].destination = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
2015-03-29 14:17:52 +02:00
|
|
|
struct TALER_DenominationPublicKey pk;
|
|
|
|
|
|
|
|
pk = *(struct TALER_DenominationPublicKey *) spec[i].destination;
|
|
|
|
if (NULL != pk.rsa_public_key)
|
|
|
|
{
|
|
|
|
GNUNET_CRYPTO_rsa_public_key_free (pk.rsa_public_key);
|
|
|
|
pk.rsa_public_key = NULL;
|
|
|
|
}
|
2015-01-29 15:45:05 +01:00
|
|
|
}
|
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
|
2015-01-29 15:45:05 +01:00
|
|
|
{
|
2015-03-29 14:17:52 +02:00
|
|
|
struct TALER_DenominationSignature sig;
|
|
|
|
|
|
|
|
sig = *(struct TALER_DenominationSignature *) spec[i].destination;
|
|
|
|
if (NULL != sig.rsa_signature)
|
|
|
|
{
|
|
|
|
GNUNET_CRYPTO_rsa_signature_free (sig.rsa_signature);
|
|
|
|
sig.rsa_signature = NULL;
|
|
|
|
}
|
2015-01-29 15:06:55 +01:00
|
|
|
}
|
|
|
|
break;
|
2015-03-27 19:58:40 +01:00
|
|
|
case TMH_PARSE_JNC_RET_AMOUNT:
|
2015-03-22 17:10:45 +01:00
|
|
|
memset (spec[i].destination,
|
|
|
|
0,
|
|
|
|
sizeof (struct TALER_Amount));
|
|
|
|
break;
|
2015-03-28 17:10:39 +01:00
|
|
|
case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
|
|
|
|
break;
|
2015-01-19 21:04:58 +01:00
|
|
|
}
|
2015-01-29 15:06:55 +01:00
|
|
|
}
|
2015-01-19 21:04:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-11 16:29:11 +02:00
|
|
|
/**
|
2015-04-11 16:32:05 +02:00
|
|
|
* Parse absolute time specified in JSON format. The JSON format is
|
|
|
|
* "/TIMEVAL/" where TIMEVAL is in milliseconds. Additionally, we
|
|
|
|
* support "/forever/" to represent the end of time.
|
2015-04-11 16:29:11 +02:00
|
|
|
*
|
|
|
|
* @param connection the MHD connection (to report errors)
|
|
|
|
* @param f json specification of the amount
|
|
|
|
* @param[out] time set to the time specified in @a f
|
|
|
|
* @return
|
|
|
|
* #GNUNET_YES if parsing was successful
|
|
|
|
* #GNUNET_NO if json is malformed, error response was generated
|
|
|
|
* #GNUNET_SYSERR on internal error, error response was not generated
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
TMH_PARSE_time_abs_json (struct MHD_Connection *connection,
|
|
|
|
json_t *f,
|
|
|
|
struct GNUNET_TIME_Absolute *time)
|
|
|
|
{
|
|
|
|
const char *val;
|
|
|
|
size_t slen;
|
|
|
|
unsigned long long int tval;
|
|
|
|
char *endp;
|
|
|
|
|
|
|
|
val = json_string_value (f);
|
|
|
|
if (NULL == val)
|
|
|
|
{
|
|
|
|
if (MHD_YES !=
|
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s}",
|
|
|
|
"error", "string expected"))
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
|
|
|
slen = strlen (val);
|
|
|
|
if ( (slen <= 2) ||
|
|
|
|
('/' != val[0]) ||
|
|
|
|
('/' != val[slen - 1]) )
|
|
|
|
{
|
|
|
|
if (MHD_YES !=
|
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:s}",
|
|
|
|
"error", "timestamp expected",
|
|
|
|
"value", val))
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
|
|
|
if (0 == strcasecmp (val,
|
|
|
|
"/forever/"))
|
|
|
|
{
|
|
|
|
*time = GNUNET_TIME_UNIT_FOREVER_ABS;
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
tval = strtoull (&val[1],
|
|
|
|
&endp,
|
|
|
|
10);
|
|
|
|
if (&val[slen - 1] != endp)
|
|
|
|
{
|
|
|
|
if (MHD_YES !=
|
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:s}",
|
|
|
|
"error", "timestamp expected",
|
|
|
|
"value", val))
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
|
|
|
/* Time is in 'ms' in JSON, but in microseconds in GNUNET_TIME_Absolute */
|
|
|
|
time->abs_value_us = tval * 1000LL;
|
|
|
|
if ( (time->abs_value_us) / 1000LL != tval)
|
|
|
|
{
|
|
|
|
/* Integer overflow */
|
|
|
|
if (MHD_YES !=
|
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:s}",
|
|
|
|
"error", "timestamp outside of legal range",
|
|
|
|
"value", val))
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-28 14:55:25 +01:00
|
|
|
/**
|
|
|
|
* Parse amount specified in JSON format.
|
|
|
|
*
|
|
|
|
* @param connection the MHD connection (to report errors)
|
|
|
|
* @param f json specification of the amount
|
2015-03-28 15:42:07 +01:00
|
|
|
* @param[out] amount set to the amount specified in @a f
|
2015-01-28 14:55:25 +01:00
|
|
|
* @return
|
|
|
|
* #GNUNET_YES if parsing was successful
|
|
|
|
* #GNUNET_NO if json is malformed, error response was generated
|
|
|
|
* #GNUNET_SYSERR on internal error, error response was not generated
|
|
|
|
*/
|
|
|
|
int
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_PARSE_amount_json (struct MHD_Connection *connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
json_t *f,
|
|
|
|
struct TALER_Amount *amount)
|
2015-01-28 14:55:25 +01:00
|
|
|
{
|
|
|
|
json_int_t value;
|
|
|
|
json_int_t fraction;
|
|
|
|
const char *currency;
|
|
|
|
|
2015-03-18 18:55:41 +01:00
|
|
|
memset (amount,
|
|
|
|
0,
|
|
|
|
sizeof (struct TALER_Amount));
|
2015-01-28 14:55:25 +01:00
|
|
|
if (-1 == json_unpack (f,
|
|
|
|
"{s:I, s:I, s:s}",
|
|
|
|
"value", &value,
|
|
|
|
"fraction", &fraction,
|
|
|
|
"currency", ¤cy))
|
|
|
|
{
|
2015-03-27 19:58:40 +01:00
|
|
|
TALER_LOG_WARNING ("Failed to parse JSON amount specification\n");
|
2015-01-28 14:55:25 +01:00
|
|
|
if (MHD_YES !=
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s}",
|
|
|
|
"error", "Bad format"))
|
2015-01-28 14:55:25 +01:00
|
|
|
return GNUNET_SYSERR;
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
|
|
|
if ( (value < 0) ||
|
|
|
|
(fraction < 0) ||
|
2015-03-18 18:55:41 +01:00
|
|
|
(value > UINT64_MAX) ||
|
2015-01-28 14:55:25 +01:00
|
|
|
(fraction > UINT32_MAX) )
|
|
|
|
{
|
2015-03-27 19:58:40 +01:00
|
|
|
TALER_LOG_WARNING ("Amount specified not in allowed range\n");
|
2015-01-28 14:55:25 +01:00
|
|
|
if (MHD_YES !=
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s}",
|
|
|
|
"error", "Amount outside of allowed range"))
|
2015-01-28 14:55:25 +01:00
|
|
|
return GNUNET_SYSERR;
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
|
|
|
if (0 != strcmp (currency,
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_MINT_CURRENCY))
|
2015-01-28 14:55:25 +01:00
|
|
|
{
|
2015-03-27 19:58:40 +01:00
|
|
|
TALER_LOG_WARNING ("Currency specified not supported by this mint\n");
|
2015-01-28 14:55:25 +01:00
|
|
|
if (MHD_YES !=
|
2015-03-27 19:58:40 +01:00
|
|
|
TMH_RESPONSE_reply_json_pack (connection,
|
2015-03-28 17:10:39 +01:00
|
|
|
MHD_HTTP_BAD_REQUEST,
|
|
|
|
"{s:s, s:s}",
|
|
|
|
"error", "Currency not supported",
|
|
|
|
"currency", currency))
|
2015-01-28 14:55:25 +01:00
|
|
|
return GNUNET_SYSERR;
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
2015-03-18 18:55:41 +01:00
|
|
|
amount->value = (uint64_t) value;
|
|
|
|
amount->fraction = (uint32_t) fraction;
|
2015-03-27 19:58:40 +01:00
|
|
|
GNUNET_assert (strlen (TMH_MINT_CURRENCY) < TALER_CURRENCY_LEN);
|
|
|
|
strcpy (amount->currency, TMH_MINT_CURRENCY);
|
2015-03-18 18:55:41 +01:00
|
|
|
TALER_amount_normalize (amount);
|
2015-01-28 14:55:25 +01:00
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-26 12:22:26 +01:00
|
|
|
|
2015-01-16 14:04:02 +01:00
|
|
|
/* end of taler-mint-httpd_parsing.c */
|