| /* |
| This file is part of libmicrohttpd |
| Copyright (C) 2007 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" |
| |
| #if 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"; |
| case MHD_TLS_CONNECTION_INIT: |
| return "secure connection init"; |
| default: |
| return "unrecognized connection state"; |
| } |
| } |
| #endif |
| #endif |
| |
| #if HAVE_MESSAGES |
| /** |
| * fprintf-like helper function for logging debug |
| * messages. |
| */ |
| void |
| MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...) |
| { |
| va_list va; |
| |
| if (0 == (daemon->options & MHD_USE_DEBUG)) |
| return; |
| va_start (va, format); |
| daemon->custom_error_log (daemon->custom_error_log_cls, format, va); |
| va_end (va); |
| } |
| #endif |
| |
| |
| /** |
| * Convert all occurences 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; |
| char *end; |
| unsigned int num; |
| char buf3[3]; |
| |
| while ('\0' != *rpos) |
| { |
| switch (*rpos) |
| { |
| case '%': |
| if ( ('\0' == rpos[1]) || |
| ('\0' == rpos[2]) ) |
| { |
| *wpos = '\0'; |
| return wpos - val; |
| } |
| buf3[0] = rpos[1]; |
| buf3[1] = rpos[2]; |
| buf3[2] = '\0'; |
| num = strtoul (buf3, &end, 16); |
| if ('\0' == *end) |
| { |
| *wpos = (char)((unsigned char) num); |
| wpos++; |
| rpos += 3; |
| break; |
| } |
| /* intentional fall through! */ |
| default: |
| *wpos = *rpos; |
| wpos++; |
| rpos++; |
| } |
| } |
| *wpos = '\0'; /* add 0-terminator */ |
| return wpos - val; /* = strlen(val) */ |
| } |
| |
| |
| /** |
| * Equivalent to time(NULL) but tries to use some sort of monotonic |
| * clock that isn't affected by someone setting the system real time |
| * clock. |
| * |
| * @return 'current' time |
| */ |
| time_t |
| MHD_monotonic_time (void) |
| { |
| #ifdef HAVE_CLOCK_GETTIME |
| #ifdef CLOCK_MONOTONIC |
| struct timespec ts; |
| |
| if (0 == clock_gettime (CLOCK_MONOTONIC, &ts)) |
| return ts.tv_sec; |
| #endif |
| #endif |
| return time (NULL); |
| } |
| |
| /* end of internal.c */ |