mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-26 04:09:30 +03:00
284 lines
7.1 KiB
C
284 lines
7.1 KiB
C
/*
|
|
This file is part of libmicrohttpd
|
|
Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/**
|
|
* @file microhttpd/internal.c
|
|
* @brief internal shared structures
|
|
* @author Daniel Pittman
|
|
* @author Christian Grothoff
|
|
*/
|
|
#include "internal.h"
|
|
#include "mhd_str.h"
|
|
|
|
#ifdef HAVE_MESSAGES
|
|
#if DEBUG_STATES
|
|
/**
|
|
* State to string dictionary.
|
|
*/
|
|
const char *
|
|
MHD_state_to_string (enum MHD_CONNECTION_STATE state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case MHD_CONNECTION_INIT:
|
|
return "connection init";
|
|
case MHD_CONNECTION_URL_RECEIVED:
|
|
return "connection url received";
|
|
case MHD_CONNECTION_HEADER_PART_RECEIVED:
|
|
return "header partially received";
|
|
case MHD_CONNECTION_HEADERS_RECEIVED:
|
|
return "headers received";
|
|
case MHD_CONNECTION_HEADERS_PROCESSED:
|
|
return "headers processed";
|
|
case MHD_CONNECTION_CONTINUE_SENDING:
|
|
return "continue sending";
|
|
case MHD_CONNECTION_CONTINUE_SENT:
|
|
return "continue sent";
|
|
case MHD_CONNECTION_BODY_RECEIVED:
|
|
return "body received";
|
|
case MHD_CONNECTION_FOOTER_PART_RECEIVED:
|
|
return "footer partially received";
|
|
case MHD_CONNECTION_FOOTERS_RECEIVED:
|
|
return "footers received";
|
|
case MHD_CONNECTION_HEADERS_SENDING:
|
|
return "headers sending";
|
|
case MHD_CONNECTION_HEADERS_SENT:
|
|
return "headers sent";
|
|
case MHD_CONNECTION_NORMAL_BODY_READY:
|
|
return "normal body ready";
|
|
case MHD_CONNECTION_NORMAL_BODY_UNREADY:
|
|
return "normal body unready";
|
|
case MHD_CONNECTION_CHUNKED_BODY_READY:
|
|
return "chunked body ready";
|
|
case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
|
|
return "chunked body unready";
|
|
case MHD_CONNECTION_BODY_SENT:
|
|
return "body sent";
|
|
case MHD_CONNECTION_FOOTERS_SENDING:
|
|
return "footers sending";
|
|
case MHD_CONNECTION_FOOTERS_SENT:
|
|
return "footers sent";
|
|
case MHD_CONNECTION_CLOSED:
|
|
return "closed";
|
|
default:
|
|
return "unrecognized connection state";
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifdef HAVE_MESSAGES
|
|
/**
|
|
* fprintf-like helper function for logging debug
|
|
* messages.
|
|
*/
|
|
void
|
|
MHD_DLOG (const struct MHD_Daemon *daemon,
|
|
enum MHD_StatusCode sc,
|
|
const char *format,
|
|
...)
|
|
{
|
|
va_list va;
|
|
|
|
if (NULL == daemon->logger)
|
|
return;
|
|
va_start (va,
|
|
format);
|
|
daemon->logger (daemon->logger_cls,
|
|
sc,
|
|
format,
|
|
va);
|
|
va_end (va);
|
|
}
|
|
#endif
|
|
|
|
|
|
/**
|
|
* Convert all occurrences of '+' to ' '.
|
|
*
|
|
* @param arg string that is modified (in place), must be 0-terminated
|
|
*/
|
|
void
|
|
MHD_unescape_plus (char *arg)
|
|
{
|
|
char *p;
|
|
|
|
for (p=strchr (arg, '+'); NULL != p; p = strchr (p + 1, '+'))
|
|
*p = ' ';
|
|
}
|
|
|
|
|
|
/**
|
|
* Process escape sequences ('%HH') Updates val in place; the
|
|
* result should be UTF-8 encoded and cannot be larger than the input.
|
|
* The result must also still be 0-terminated.
|
|
*
|
|
* @param val value to unescape (modified in the process)
|
|
* @return length of the resulting val (strlen(val) maybe
|
|
* shorter afterwards due to elimination of escape sequences)
|
|
*/
|
|
size_t
|
|
MHD_http_unescape (char *val)
|
|
{
|
|
char *rpos = val;
|
|
char *wpos = val;
|
|
|
|
while ('\0' != *rpos)
|
|
{
|
|
uint32_t num;
|
|
switch (*rpos)
|
|
{
|
|
case '%':
|
|
if (2 == MHD_strx_to_uint32_n_ (rpos + 1,
|
|
2,
|
|
&num))
|
|
{
|
|
*wpos = (char)((unsigned char) num);
|
|
wpos++;
|
|
rpos += 3;
|
|
break;
|
|
}
|
|
/* TODO: add bad sequence handling */
|
|
/* intentional fall through! */
|
|
default:
|
|
*wpos = *rpos;
|
|
wpos++;
|
|
rpos++;
|
|
}
|
|
}
|
|
*wpos = '\0'; /* add 0-terminator */
|
|
return wpos - val; /* = strlen(val) */
|
|
}
|
|
|
|
|
|
/**
|
|
* Parse and unescape the arguments given by the client
|
|
* as part of the HTTP request URI.
|
|
*
|
|
* @param request request to add headers to
|
|
* @param kind header kind to pass to @a cb
|
|
* @param[in,out] args argument URI string (after "?" in URI),
|
|
* clobbered in the process!
|
|
* @param cb function to call on each key-value pair found
|
|
* @param[out] num_headers set to the number of headers found
|
|
* @return false on failure (@a cb returned false),
|
|
* true for success (parsing succeeded, @a cb always
|
|
* returned true)
|
|
*/
|
|
bool
|
|
MHD_parse_arguments_ (struct MHD_Request *request,
|
|
enum MHD_ValueKind kind,
|
|
char *args,
|
|
MHD_ArgumentIterator_ cb,
|
|
unsigned int *num_headers)
|
|
{
|
|
struct MHD_Daemon *daemon = request->daemon;
|
|
char *equals;
|
|
char *amper;
|
|
|
|
*num_headers = 0;
|
|
while ( (NULL != args) &&
|
|
('\0' != args[0]) )
|
|
{
|
|
equals = strchr (args, '=');
|
|
amper = strchr (args, '&');
|
|
if (NULL == amper)
|
|
{
|
|
/* last argument */
|
|
if (NULL == equals)
|
|
{
|
|
/* last argument, without '=' */
|
|
MHD_unescape_plus (args);
|
|
daemon->unescape_cb (daemon->unescape_cb_cls,
|
|
request,
|
|
args);
|
|
if (! cb (request,
|
|
args,
|
|
NULL,
|
|
kind))
|
|
return false;
|
|
(*num_headers)++;
|
|
break;
|
|
}
|
|
/* got 'foo=bar' */
|
|
equals[0] = '\0';
|
|
equals++;
|
|
MHD_unescape_plus (args);
|
|
daemon->unescape_cb (daemon->unescape_cb_cls,
|
|
request,
|
|
args);
|
|
MHD_unescape_plus (equals);
|
|
daemon->unescape_cb (daemon->unescape_cb_cls,
|
|
request,
|
|
equals);
|
|
if (! cb (request,
|
|
args,
|
|
equals,
|
|
kind))
|
|
return false;
|
|
(*num_headers)++;
|
|
break;
|
|
}
|
|
/* amper is non-NULL here */
|
|
amper[0] = '\0';
|
|
amper++;
|
|
if ( (NULL == equals) ||
|
|
(equals >= amper) )
|
|
{
|
|
/* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
|
|
MHD_unescape_plus (args);
|
|
daemon->unescape_cb (daemon->unescape_cb_cls,
|
|
request,
|
|
args);
|
|
if (! cb (request,
|
|
args,
|
|
NULL,
|
|
kind))
|
|
return false;
|
|
/* continue with 'bar' */
|
|
(*num_headers)++;
|
|
args = amper;
|
|
continue;
|
|
}
|
|
/* equals and amper are non-NULL here, and equals < amper,
|
|
so we got regular 'foo=value&bar...'-kind of argument */
|
|
equals[0] = '\0';
|
|
equals++;
|
|
MHD_unescape_plus (args);
|
|
daemon->unescape_cb (daemon->unescape_cb_cls,
|
|
request,
|
|
args);
|
|
MHD_unescape_plus (equals);
|
|
daemon->unescape_cb (daemon->unescape_cb_cls,
|
|
request,
|
|
equals);
|
|
if (! cb (request,
|
|
args,
|
|
equals,
|
|
kind))
|
|
return false;
|
|
(*num_headers)++;
|
|
args = amper;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* end of internal.c */
|