Blame src/microhttpd/internal.c

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