Revert "Use a variable on the stack to not have a temporary in the call"
[ACE_TAO.git] / ACE / apps / JAWS / server / HTTP_Helpers.cpp
bloba9f778dda39294547324f4ee0e3ce73466776b81
1 // HTTP_Helpers.cpp -- Helper utilities for both server and client
3 #include "HTTP_Helpers.h"
4 #include "ace/Log_Msg.h"
5 #include "ace/OS_NS_string.h"
6 #include "ace/Guard_T.h"
7 #include "ace/OS_NS_time.h"
8 #include "ace/OS_NS_stdio.h"
10 // = Static initialization.
11 const char *const
12 HTTP_Helper::months_[12]=
14 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
15 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
18 char const *HTTP_Helper::alphabet_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
20 char * HTTP_Helper::date_string_ = 0;
21 ACE_SYNCH_MUTEX HTTP_Helper::mutex_;
23 ACE_SYNCH_MUTEX HTTP_Status_Code::lock_;
24 int HTTP_Status_Code::instance_ = 0;
25 const char *HTTP_Status_Code::Reason[HTTP_Status_Code::MAX_STATUS_CODE + 1];
27 time_t
28 HTTP_Helper::HTTP_mktime (const char *httpdate)
30 char *buf;
32 ACE_NEW_RETURN (buf, char[ACE_OS::strlen (httpdate) + 1], (time_t) -1);
34 // Make spaces in the date be semi-colons so we can parse robustly
35 // with sscanf.
37 const char *ptr1 = httpdate;
38 char *ptr2 = buf;
42 if (*ptr1 == ' ')
43 *ptr2++ = ';';
44 else
45 *ptr2++ = *ptr1;
47 while (*ptr1++ != '\0');
49 // In HTTP/1.0, there are three versions of an HTTP_date.
51 // rfc1123-date = wkday "," SP dd month yyyy SP hh:mm:ss SP "GMT"
52 // rfc850-date = weekday "," SP dd-month-yy SP hh:mm:ss SP "GMT"
53 // asctime-date = wkday SP month dd SP hh:mm:ss SP yyyy
55 // static const char rfc1123_date[] = "%3s,;%2d;%3s;%4d;%2d:%2d:%2d;GMT";
56 // static const char rfc850_date[] = "%s,;%2d-%3s-%2d;%2d:%2d:%2d;GMT";
57 // static const char asctime_date[] = "%3s;%3s;%2d;%2d:%2d:%2d;%4d";
59 // Should also support other versions (such as from NNTP and SMTP)
60 // for robustness, but it should be clear how to extend this.
62 struct tm tms;
63 char month[4];
64 char weekday[10];
66 if (::sscanf(buf, "%3s,;%2d;%3s;%4d;%2d:%2d:%2d;GMT", // RFC-1123 date format
67 weekday,
68 &tms.tm_mday,
69 month,
70 &tms.tm_year,
71 &tms.tm_hour,
72 &tms.tm_min,
73 &tms.tm_sec) == 7)
75 else if (::sscanf(buf, "%s,;%2d-%3s-%2d;%2d:%2d:%2d;GMT", // RFC-850 date format
76 weekday,
77 &tms.tm_mday, month, &tms.tm_year,
78 &tms.tm_hour, &tms.tm_min, &tms.tm_sec) == 7)
80 weekday[3] = '\0';
82 else if (::sscanf(buf, "%3s;%3s;%2d;%2d:%2d:%2d;%4d", // ASCTIME date format.
83 weekday,
84 month, &tms.tm_mday,
85 &tms.tm_hour, &tms.tm_min, &tms.tm_sec,
86 &tms.tm_year) == 7)
90 delete [] buf;
92 tms.tm_year = HTTP_Helper::fixyear (tms.tm_year);
93 tms.tm_mon = HTTP_Helper::HTTP_month (month);
95 if (tms.tm_mon == -1)
96 return (time_t) -1;
98 // mktime is a Standard C function.
100 #if !defined (ACE_HAS_REENTRANT_LIBC)
101 ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, g, HTTP_Helper::mutex_, -1));
102 #endif /* NOT ACE_HAS_REENTRANT_LIBC */
104 return ACE_OS::mktime (&tms);
108 const char *
109 HTTP_Helper::HTTP_date ()
111 if (HTTP_Helper::date_string_ == 0)
113 ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, m, HTTP_Helper::mutex_, 0));
115 if (HTTP_Helper::date_string_ == 0)
117 // 40 bytes is all I need.
118 ACE_NEW_RETURN (HTTP_Helper::date_string_, char[40], 0);
120 if (!HTTP_Helper::HTTP_date (HTTP_Helper::date_string_))
122 delete [] HTTP_Helper::date_string_;
123 HTTP_Helper::date_string_ = 0;
128 return HTTP_Helper::date_string_;
131 const char *
132 HTTP_Helper::HTTP_date (char *s)
134 // Return the date-string formatted per HTTP standards. Time must
135 // be in UTC, so using the 'strftime' call (which obeys the locale)
136 // isn't correct.
137 static const char* months[] = {"Jan","Feb","Mar","Apr","May","Jun",
138 "Jul","Aug","Sep","Oct","Nov","Dec"};
139 static const char* days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
141 time_t tloc;
142 struct tm tms;
143 char * date_string = s;
145 if (ACE_OS::time (&tloc) != (time_t) -1
146 && ACE_OS::gmtime_r (&tloc, &tms) != 0)
148 ACE_OS::sprintf (date_string,
149 "%s, %2.2d %s %4.4d %2.2d:%2.2d:%2.2d GMT",
150 days[tms.tm_wday], tms.tm_mday, months[tms.tm_mon],
151 tms.tm_year + 1900, tms.tm_hour, tms.tm_min, tms.tm_sec);
153 else
154 date_string = 0;
156 return date_string;
160 HTTP_Helper::HTTP_month (const char *month)
162 for (size_t i = 0; i < 12; i++)
163 if (ACE_OS::strcmp(month, HTTP_Helper::months_[i]) == 0)
164 return i;
166 return -1;
169 const char *
170 HTTP_Helper::HTTP_month (int month)
172 if (month < 0 || month >= 12)
173 return 0;
175 return HTTP_Helper::months_[month];
178 // Fix the path if it needs fixing/is fixable.
180 char *
181 HTTP_Helper::HTTP_decode_string (char *path)
183 // replace the percentcodes with the actual character
184 int i, j;
185 char percentcode[3];
187 for (i = j = 0; path[i] != '\0'; i++, j++)
189 if (path[i] == '%')
191 percentcode[0] = path[++i];
192 percentcode[1] = path[++i];
193 percentcode[2] = '\0';
194 path[j] = (char) ACE_OS::strtol (percentcode, (char **) 0, 16);
196 else
197 path[j] = path[i];
200 path[j] = path[i];
202 return path;
205 char *
206 HTTP_Helper::HTTP_decode_base64 (char *data)
208 char inalphabet[256], decoder[256];
210 ACE_OS::memset (inalphabet, 0, sizeof (inalphabet));
211 ACE_OS::memset (decoder, 0, sizeof (decoder));
213 for (int i = ACE_OS::strlen (HTTP_Helper::alphabet_) - 1;
214 i >= 0;
215 i--)
217 inalphabet[(unsigned int) HTTP_Helper::alphabet_[i]] = 1;
218 decoder[(unsigned int) HTTP_Helper::alphabet_[i]] = i;
221 char *indata = data;
222 char *outdata = data;
224 int bits = 0;
225 int c;
226 int char_count = 0;
227 int errors = 0;
229 while ((c = *indata++) != '\0')
231 if (c == '=')
232 break;
233 if (c > 255 || ! inalphabet[c])
234 continue;
235 bits += decoder[c];
236 char_count++;
237 if (char_count == 4)
239 *outdata++ = (bits >> 16);
240 *outdata++ = ((bits >> 8) & 0xff);
241 *outdata++ = (bits & 0xff);
242 bits = 0;
243 char_count = 0;
245 else
246 bits <<= 6;
249 if (c == '\0')
251 if (char_count)
253 ACE_DEBUG ((LM_DEBUG,
254 "base64 encoding incomplete: at least %d bits truncated\n",
255 ((4 - char_count) * 6)));
256 errors++;
259 else
261 // c == '='
262 switch (char_count)
264 case 1:
265 ACE_DEBUG ((LM_DEBUG,
266 "base64 encoding incomplete: at least 2 bits missing\n"));
267 errors++;
268 break;
269 case 2:
270 *outdata++ = (bits >> 10);
271 break;
272 case 3:
273 *outdata++ = (bits >> 16);
274 *outdata++ = ((bits >> 8) & 0xff);
275 break;
278 *outdata = '\0';
279 return errors ? 0 : data;
282 char *
283 HTTP_Helper::HTTP_encode_base64 (char *data)
285 char buf[BUFSIZ];
286 int c;
287 int error;
288 int char_count = 0;
289 int bits = 0;
290 error = 0;
291 char *indata = data;
292 char *outdata = buf;
293 const unsigned char ASCII_MAX = ~0;
295 while ((c = *indata++) != '\0')
297 if (c > (int)ASCII_MAX)
299 ACE_DEBUG ((LM_DEBUG, "encountered char > 255 (decimal %d)\n", c));
300 error++;
301 break;
303 bits += c;
304 char_count++;
306 if (char_count == 3)
308 *outdata++ = HTTP_Helper::alphabet_[bits >> 18];
309 *outdata++ = HTTP_Helper::alphabet_[(bits >> 12) & 0x3f];
310 *outdata++ = HTTP_Helper::alphabet_[(bits >> 6) & 0x3f];
311 *outdata++ = HTTP_Helper::alphabet_[bits & 0x3f];
312 bits = 0;
313 char_count = 0;
315 else
316 bits <<= 8;
319 if (!error)
321 if (char_count != 0)
323 bits <<= 16 - (8 * char_count);
324 *outdata++ = HTTP_Helper::alphabet_[bits >> 18];
325 *outdata++ = HTTP_Helper::alphabet_[(bits >> 12) & 0x3f];
327 if (char_count == 1)
329 *outdata++ = '=';
330 *outdata++ = '=';
332 else
334 *outdata++ = HTTP_Helper::alphabet_[(bits >> 6) & 0x3f];
335 *outdata++ = '=';
338 *outdata = '\0';
339 ACE_OS::strcpy (data, buf);
342 return (error ? 0 : data);
346 HTTP_Helper::fixyear (int year)
348 // Fix the year 2000 problem
350 if (year > 1000)
351 year -= 1900;
352 else if (year < 100)
354 struct tm tms;
355 time_t tloc;
357 if (ACE_OS::time (&tloc) != (time_t) -1)
359 ACE_OS::gmtime_r (&tloc, &tms);
361 if (tms.tm_year % 100 == year)
362 year = tms.tm_year;
364 // The last two cases check boundary conditions, in case the
365 // year just changed at the moment we checked to see if we
366 // need to fix it.
367 if ((year+1) % 100 == tms.tm_year % 100)
368 year = tms.tm_year - 1;
370 if (year == (tms.tm_year + 1) % 100)
371 year = tms.tm_year + 1;
373 // What to do if none of the above?
377 return year;
380 const char **
381 HTTP_Status_Code::instance ()
383 if (HTTP_Status_Code::instance_ == 0)
385 ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, g, lock_, 0));
387 if (HTTP_Status_Code::instance_ == 0)
389 for (size_t i = 0;
390 i < HTTP_Status_Code::MAX_STATUS_CODE + 1;
391 i++)
393 switch (i)
395 case STATUS_OK:
396 HTTP_Status_Code::Reason[i] = "OK"; break;
397 case STATUS_CREATED:
398 HTTP_Status_Code::Reason[i] = "Created"; break;
399 case STATUS_ACCEPTED:
400 HTTP_Status_Code::Reason[i] = "Accepted"; break;
401 case STATUS_NO_CONTENT:
402 HTTP_Status_Code::Reason[i] = "No Content"; break;
403 case STATUS_MOVED_PERMANENTLY:
404 HTTP_Status_Code::Reason[i] = "Moved Permanently"; break;
405 case STATUS_MOVED_TEMPORARILY:
406 HTTP_Status_Code::Reason[i] = "Moved Temporarily"; break;
407 case STATUS_NOT_MODIFIED:
408 HTTP_Status_Code::Reason[i] = "Not Modified"; break;
409 case STATUS_BAD_REQUEST:
410 HTTP_Status_Code::Reason[i] = "Bad Request"; break;
411 case STATUS_UNAUTHORIZED:
412 HTTP_Status_Code::Reason[i] = "Unauthorized"; break;
413 case STATUS_FORBIDDEN:
414 HTTP_Status_Code::Reason[i] = "Forbidden"; break;
415 case STATUS_NOT_FOUND:
416 HTTP_Status_Code::Reason[i] = "Not Found"; break;
417 case STATUS_INTERNAL_SERVER_ERROR:
418 HTTP_Status_Code::Reason[i] = "Internal Server Error"; break;
419 case STATUS_NOT_IMPLEMENTED:
420 HTTP_Status_Code::Reason[i] = "Not Implemented"; break;
421 case STATUS_BAD_GATEWAY:
422 HTTP_Status_Code::Reason[i] = "Bad Gateway"; break;
423 case STATUS_SERVICE_UNAVAILABLE:
424 HTTP_Status_Code::Reason[i] = "Service Unavailable"; break;
425 default:
426 HTTP_Status_Code::Reason[i] = "Unknown";
430 HTTP_Status_Code::instance_ = 1;
433 // GUARD released
436 return HTTP_Status_Code::Reason;