1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007 Daniel Pittman and Christian Grothoff 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /** 21 * @file microhttpd/internal.c 22 * @brief internal shared structures 23 * @author Daniel Pittman 24 * @author Christian Grothoff 25 */ 26 27 #include "internal.h" 28 29 #if HAVE_MESSAGES 30 #if DEBUG_STATES 31 /** 32 * State to string dictionary. 33 */ 34 const char * 35 MHD_state_to_string (enum MHD_CONNECTION_STATE state) 36 { 37 switch (state) 38 { 39 case MHD_CONNECTION_INIT: 40 return "connection init"; 41 case MHD_CONNECTION_URL_RECEIVED: 42 return "connection url received"; 43 case MHD_CONNECTION_HEADER_PART_RECEIVED: 44 return "header partially received"; 45 case MHD_CONNECTION_HEADERS_RECEIVED: 46 return "headers received"; 47 case MHD_CONNECTION_HEADERS_PROCESSED: 48 return "headers processed"; 49 case MHD_CONNECTION_CONTINUE_SENDING: 50 return "continue sending"; 51 case MHD_CONNECTION_CONTINUE_SENT: 52 return "continue sent"; 53 case MHD_CONNECTION_BODY_RECEIVED: 54 return "body received"; 55 case MHD_CONNECTION_FOOTER_PART_RECEIVED: 56 return "footer partially received"; 57 case MHD_CONNECTION_FOOTERS_RECEIVED: 58 return "footers received"; 59 case MHD_CONNECTION_HEADERS_SENDING: 60 return "headers sending"; 61 case MHD_CONNECTION_HEADERS_SENT: 62 return "headers sent"; 63 case MHD_CONNECTION_NORMAL_BODY_READY: 64 return "normal body ready"; 65 case MHD_CONNECTION_NORMAL_BODY_UNREADY: 66 return "normal body unready"; 67 case MHD_CONNECTION_CHUNKED_BODY_READY: 68 return "chunked body ready"; 69 case MHD_CONNECTION_CHUNKED_BODY_UNREADY: 70 return "chunked body unready"; 71 case MHD_CONNECTION_BODY_SENT: 72 return "body sent"; 73 case MHD_CONNECTION_FOOTERS_SENDING: 74 return "footers sending"; 75 case MHD_CONNECTION_FOOTERS_SENT: 76 return "footers sent"; 77 case MHD_CONNECTION_CLOSED: 78 return "closed"; 79 case MHD_TLS_CONNECTION_INIT: 80 return "secure connection init"; 81 default: 82 return "unrecognized connection state"; 83 } 84 } 85 #endif 86 #endif 87 88 #if HAVE_MESSAGES 89 /** 90 * fprintf-like helper function for logging debug 91 * messages. 92 */ 93 void 94 MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...) 95 { 96 va_list va; 97 98 if (0 == (daemon->options & MHD_USE_DEBUG)) 99 return; 100 va_start (va, format); 101 daemon->custom_error_log (daemon->custom_error_log_cls, format, va); 102 va_end (va); 103 } 104 #endif 105 106 107 /** 108 * Convert all occurences of '+' to ' '. 109 * 110 * @param arg string that is modified (in place), must be 0-terminated 111 */ 112 void 113 MHD_unescape_plus (char *arg) 114 { 115 char *p; 116 117 for (p=strchr (arg, '+'); NULL != p; p = strchr (p + 1, '+')) 118 *p = ' '; 119 } 120 121 122 /** 123 * Process escape sequences ('%HH') Updates val in place; the 124 * result should be UTF-8 encoded and cannot be larger than the input. 125 * The result must also still be 0-terminated. 126 * 127 * @param val value to unescape (modified in the process) 128 * @return length of the resulting val (strlen(val) maybe 129 * shorter afterwards due to elimination of escape sequences) 130 */ 131 size_t 132 MHD_http_unescape (char *val) 133 { 134 char *rpos = val; 135 char *wpos = val; 136 char *end; 137 unsigned int num; 138 char buf3[3]; 139 140 while ('\0' != *rpos) 141 { 142 switch (*rpos) 143 { 144 case '%': 145 if ( ('\0' == rpos[1]) || 146 ('\0' == rpos[2]) ) 147 { 148 *wpos = '\0'; 149 return wpos - val; 150 } 151 buf3[0] = rpos[1]; 152 buf3[1] = rpos[2]; 153 buf3[2] = '\0'; 154 num = strtoul (buf3, &end, 16); 155 if ('\0' == *end) 156 { 157 *wpos = (char)((unsigned char) num); 158 wpos++; 159 rpos += 3; 160 break; 161 } 162 /* intentional fall through! */ 163 default: 164 *wpos = *rpos; 165 wpos++; 166 rpos++; 167 } 168 } 169 *wpos = '\0'; /* add 0-terminator */ 170 return wpos - val; /* = strlen(val) */ 171 } 172 173 174 /** 175 * Equivalent to time(NULL) but tries to use some sort of monotonic 176 * clock that isn't affected by someone setting the system real time 177 * clock. 178 * 179 * @return 'current' time 180 */ 181 time_t 182 MHD_monotonic_time (void) 183 { 184 #ifdef HAVE_CLOCK_GETTIME 185 #ifdef CLOCK_MONOTONIC 186 struct timespec ts; 187 188 if (0 == clock_gettime (CLOCK_MONOTONIC, &ts)) 189 return ts.tv_sec; 190 #endif 191 #endif 192 return time (NULL); 193 } 194 195 /* end of internal.c */ 196