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 *
MHD_state_to_string(enum MHD_CONNECTION_STATE state)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
MHD_DLOG(const struct MHD_Daemon * daemon,const char * format,...)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
MHD_unescape_plus(char * arg)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
MHD_http_unescape(char * val)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
MHD_monotonic_time(void)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