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