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.
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];
28 HTTP_Helper::HTTP_mktime (const char *httpdate
)
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
37 const char *ptr1
= httpdate
;
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.
66 if (::sscanf(buf
, "%3s,;%2d;%3s;%4d;%2d:%2d:%2d;GMT", // RFC-1123 date format
75 else if (::sscanf(buf
, "%s,;%2d-%3s-%2d;%2d:%2d:%2d;GMT", // RFC-850 date format
77 &tms
.tm_mday
, month
, &tms
.tm_year
,
78 &tms
.tm_hour
, &tms
.tm_min
, &tms
.tm_sec
) == 7)
82 else if (::sscanf(buf
, "%3s;%3s;%2d;%2d:%2d:%2d;%4d", // ASCTIME date format.
85 &tms
.tm_hour
, &tms
.tm_min
, &tms
.tm_sec
,
92 tms
.tm_year
= HTTP_Helper::fixyear (tms
.tm_year
);
93 tms
.tm_mon
= HTTP_Helper::HTTP_month (month
);
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
);
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_
;
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)
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"};
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
);
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)
170 HTTP_Helper::HTTP_month (int month
)
172 if (month
< 0 || month
>= 12)
175 return HTTP_Helper::months_
[month
];
178 // Fix the path if it needs fixing/is fixable.
181 HTTP_Helper::HTTP_decode_string (char *path
)
183 // replace the percentcodes with the actual character
187 for (i
= j
= 0; path
[i
] != '\0'; i
++, j
++)
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);
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;
217 inalphabet
[(unsigned int) HTTP_Helper::alphabet_
[i
]] = 1;
218 decoder
[(unsigned int) HTTP_Helper::alphabet_
[i
]] = i
;
222 char *outdata
= data
;
229 while ((c
= *indata
++) != '\0')
233 if (c
> 255 || ! inalphabet
[c
])
239 *outdata
++ = (bits
>> 16);
240 *outdata
++ = ((bits
>> 8) & 0xff);
241 *outdata
++ = (bits
& 0xff);
253 ACE_DEBUG ((LM_DEBUG
,
254 "base64 encoding incomplete: at least %d bits truncated\n",
255 ((4 - char_count
) * 6)));
265 ACE_DEBUG ((LM_DEBUG
,
266 "base64 encoding incomplete: at least 2 bits missing\n"));
270 *outdata
++ = (bits
>> 10);
273 *outdata
++ = (bits
>> 16);
274 *outdata
++ = ((bits
>> 8) & 0xff);
279 return errors
? 0 : data
;
283 HTTP_Helper::HTTP_encode_base64 (char *data
)
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
));
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];
323 bits
<<= 16 - (8 * char_count
);
324 *outdata
++ = HTTP_Helper::alphabet_
[bits
>> 18];
325 *outdata
++ = HTTP_Helper::alphabet_
[(bits
>> 12) & 0x3f];
334 *outdata
++ = HTTP_Helper::alphabet_
[(bits
>> 6) & 0x3f];
339 ACE_OS::strcpy (data
, buf
);
342 return (error
? 0 : data
);
346 HTTP_Helper::fixyear (int year
)
348 // Fix the year 2000 problem
357 if (ACE_OS::time (&tloc
) != (time_t) -1)
359 ACE_OS::gmtime_r (&tloc
, &tms
);
361 if (tms
.tm_year
% 100 == 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
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?
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)
390 i
< HTTP_Status_Code::MAX_STATUS_CODE
+ 1;
396 HTTP_Status_Code::Reason
[i
] = "OK"; break;
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;
426 HTTP_Status_Code::Reason
[i
] = "Unknown";
430 HTTP_Status_Code::instance_
= 1;
436 return HTTP_Status_Code::Reason
;