libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

internal.c (8073B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007 Daniel Pittman and Christian Grothoff
      4      Copyright (C) 2015-2023 Evgeny Grin (Karlson2k)
      5 
      6      This library is free software; you can redistribute it and/or
      7      modify it under the terms of the GNU Lesser General Public
      8      License as published by the Free Software Foundation; either
      9      version 2.1 of the License, or (at your option) any later version.
     10 
     11      This library is distributed in the hope that it will be useful,
     12      but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14      Lesser General Public License for more details.
     15 
     16      You should have received a copy of the GNU Lesser General Public
     17      License along with this library; if not, write to the Free Software
     18      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     19 */
     20 
     21 /**
     22  * @file microhttpd/internal.c
     23  * @brief  internal shared structures
     24  * @author Daniel Pittman
     25  * @author Christian Grothoff
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 
     29 #include "internal.h"
     30 #include "mhd_str.h"
     31 
     32 #ifdef HAVE_MESSAGES
     33 #if DEBUG_STATES
     34 /**
     35  * State to string dictionary.
     36  */
     37 const char *
     38 MHD_state_to_string (enum MHD_CONNECTION_STATE state)
     39 {
     40   switch (state)
     41   {
     42   case MHD_CONNECTION_INIT:
     43     return "connection init";
     44   case MHD_CONNECTION_REQ_LINE_RECEIVING:
     45     return "receiving request line";
     46   case MHD_CONNECTION_REQ_LINE_RECEIVED:
     47     return "request line received";
     48   case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
     49     return "headers receiving";
     50   case MHD_CONNECTION_HEADERS_RECEIVED:
     51     return "headers received";
     52   case MHD_CONNECTION_HEADERS_PROCESSED:
     53     return "headers processed";
     54   case MHD_CONNECTION_CONTINUE_SENDING:
     55     return "continue sending";
     56   case MHD_CONNECTION_BODY_RECEIVING:
     57     return "body receiving";
     58   case MHD_CONNECTION_BODY_RECEIVED:
     59     return "body received";
     60   case MHD_CONNECTION_FOOTERS_RECEIVING:
     61     return "footers receiving";
     62   case MHD_CONNECTION_FOOTERS_RECEIVED:
     63     return "footers received";
     64   case MHD_CONNECTION_FULL_REQ_RECEIVED:
     65     return "full request received";
     66   case MHD_CONNECTION_START_REPLY:
     67     return "start sending reply";
     68   case MHD_CONNECTION_HEADERS_SENDING:
     69     return "headers sending";
     70   case MHD_CONNECTION_HEADERS_SENT:
     71     return "headers sent";
     72   case MHD_CONNECTION_NORMAL_BODY_UNREADY:
     73     return "normal body unready";
     74   case MHD_CONNECTION_NORMAL_BODY_READY:
     75     return "normal body ready";
     76   case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
     77     return "chunked body unready";
     78   case MHD_CONNECTION_CHUNKED_BODY_READY:
     79     return "chunked body ready";
     80   case MHD_CONNECTION_CHUNKED_BODY_SENT:
     81     return "chunked body sent";
     82   case MHD_CONNECTION_FOOTERS_SENDING:
     83     return "footers sending";
     84   case MHD_CONNECTION_FULL_REPLY_SENT:
     85     return "reply sent completely";
     86   case MHD_CONNECTION_CLOSED:
     87     return "closed";
     88   default:
     89     return "unrecognized connection state";
     90   }
     91 }
     92 
     93 
     94 #endif
     95 #endif
     96 
     97 
     98 #ifdef HAVE_MESSAGES
     99 /**
    100  * fprintf-like helper function for logging debug
    101  * messages.
    102  */
    103 void
    104 MHD_DLOG (const struct MHD_Daemon *daemon,
    105           const char *format,
    106           ...)
    107 {
    108   va_list va;
    109 
    110   if (0 == (daemon->options & MHD_USE_ERROR_LOG))
    111     return;
    112   va_start (va, format);
    113   daemon->custom_error_log (daemon->custom_error_log_cls,
    114                             format,
    115                             va);
    116   va_end (va);
    117 }
    118 
    119 
    120 #endif
    121 
    122 
    123 /**
    124  * Convert all occurrences of '+' to ' '.
    125  *
    126  * @param arg string that is modified (in place), must be 0-terminated
    127  */
    128 void
    129 MHD_unescape_plus (char *arg)
    130 {
    131   char *p;
    132 
    133   for (p = strchr (arg, '+'); NULL != p; p = strchr (p + 1, '+'))
    134     *p = ' ';
    135 }
    136 
    137 
    138 /**
    139  * Process escape sequences ('%HH') Updates val in place; the
    140  * result cannot be larger than the input.
    141  * The result is still be 0-terminated.
    142  *
    143  * @param val value to unescape (modified in the process)
    144  * @return length of the resulting val (`strlen(val)` may be
    145  *  shorter afterwards due to elimination of escape sequences)
    146  */
    147 _MHD_EXTERN size_t
    148 MHD_http_unescape (char *val)
    149 {
    150   return MHD_str_pct_decode_in_place_lenient_ (val, NULL);
    151 }
    152 
    153 
    154 /**
    155  * Parse and unescape the arguments given by the client
    156  * as part of the HTTP request URI.
    157  *
    158  * @param kind header kind to pass to @a cb
    159  * @param connection connection to add headers to
    160  * @param[in,out] args argument URI string (after "?" in URI),
    161  *        clobbered in the process!
    162  * @param cb function to call on each key-value pair found
    163  * @param cls the iterator context
    164  * @return #MHD_NO on failure (@a cb returned #MHD_NO),
    165  *         #MHD_YES for success (parsing succeeded, @a cb always
    166  *                               returned #MHD_YES)
    167  */
    168 enum MHD_Result
    169 MHD_parse_arguments_ (struct MHD_Connection *connection,
    170                       enum MHD_ValueKind kind,
    171                       char *args,
    172                       MHD_ArgumentIterator_ cb,
    173                       void *cls)
    174 {
    175   struct MHD_Daemon *daemon = connection->daemon;
    176   char *equals;
    177   char *amper;
    178 
    179   while ( (NULL != args) &&
    180           ('\0' != args[0]) )
    181   {
    182     size_t key_len;
    183     size_t value_len;
    184     equals = strchr (args, '=');
    185     amper = strchr (args, '&');
    186     if (NULL == amper)
    187     {
    188       /* last argument */
    189       if (NULL == equals)
    190       {
    191         /* last argument, without '=' */
    192         MHD_unescape_plus (args);
    193         key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
    194                                              connection,
    195                                              args);
    196         if (MHD_NO == cb (cls,
    197                           args,
    198                           key_len,
    199                           NULL,
    200                           0,
    201                           kind))
    202           return MHD_NO;
    203         break;
    204       }
    205       /* got 'foo=bar' */
    206       equals[0] = '\0';
    207       equals++;
    208       MHD_unescape_plus (args);
    209       key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
    210                                            connection,
    211                                            args);
    212       MHD_unescape_plus (equals);
    213       value_len = daemon->unescape_callback (daemon->unescape_callback_cls,
    214                                              connection,
    215                                              equals);
    216       if (MHD_NO == cb (cls,
    217                         args,
    218                         key_len,
    219                         equals,
    220                         value_len,
    221                         kind))
    222         return MHD_NO;
    223       break;
    224     }
    225     /* amper is non-NULL here */
    226     amper[0] = '\0';
    227     amper++;
    228     if ( (NULL == equals) ||
    229          (equals >= amper) )
    230     {
    231       /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
    232       MHD_unescape_plus (args);
    233       key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
    234                                            connection,
    235                                            args);
    236       if (MHD_NO == cb (cls,
    237                         args,
    238                         key_len,
    239                         NULL,
    240                         0,
    241                         kind))
    242         return MHD_NO;
    243       /* continue with 'bar' */
    244       args = amper;
    245       continue;
    246     }
    247     /* equals and amper are non-NULL here, and equals < amper,
    248  so we got regular 'foo=value&bar...'-kind of argument */
    249     equals[0] = '\0';
    250     equals++;
    251     MHD_unescape_plus (args);
    252     key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
    253                                          connection,
    254                                          args);
    255     MHD_unescape_plus (equals);
    256     value_len = daemon->unescape_callback (daemon->unescape_callback_cls,
    257                                            connection,
    258                                            equals);
    259     if (MHD_NO == cb (cls,
    260                       args,
    261                       key_len,
    262                       equals,
    263                       value_len,
    264                       kind))
    265       return MHD_NO;
    266     args = amper;
    267   }
    268   return MHD_YES;
    269 }
    270 
    271 
    272 /* end of internal.c */