diff options
Diffstat (limited to 'ACE/apps/JAWS/server/HTTP_Helpers.cpp')
-rw-r--r-- | ACE/apps/JAWS/server/HTTP_Helpers.cpp | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/ACE/apps/JAWS/server/HTTP_Helpers.cpp b/ACE/apps/JAWS/server/HTTP_Helpers.cpp new file mode 100644 index 00000000000..1ca6bfe198d --- /dev/null +++ b/ACE/apps/JAWS/server/HTTP_Helpers.cpp @@ -0,0 +1,442 @@ +// $Id$ + +// HTTP_Helpers.cpp -- Helper utilities for both server and client + +#include "HTTP_Helpers.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_string.h" +#include "ace/Guard_T.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_stdio.h" + +ACE_RCSID(server, HTTP_Helpers, "$Id$") + +// = Static initialization. +const char *const +HTTP_Helper::months_[12]= +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +char const *HTTP_Helper::alphabet_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +char * HTTP_Helper::date_string_ = 0; +ACE_SYNCH_MUTEX HTTP_Helper::mutex_; + +ACE_SYNCH_MUTEX HTTP_Status_Code::lock_; +int HTTP_Status_Code::instance_ = 0; +const char *HTTP_Status_Code::Reason[HTTP_Status_Code::MAX_STATUS_CODE + 1]; + +time_t +HTTP_Helper::HTTP_mktime (const char *httpdate) +{ + char *buf; + + ACE_NEW_RETURN (buf, char[ACE_OS::strlen (httpdate) + 1], (time_t) -1); + + // Make spaces in the date be semi-colons so we can parse robustly + // with sscanf. + + const char *ptr1 = httpdate; + char *ptr2 = buf; + + do + { + if (*ptr1 == ' ') + *ptr2++ = ';'; + else + *ptr2++ = *ptr1; + } + while (*ptr1++ != '\0'); + + // In HTTP/1.0, there are three versions of an HTTP_date. + + // rfc1123-date = wkday "," SP dd month yyyy SP hh:mm:ss SP "GMT" + // rfc850-date = weekday "," SP dd-month-yy SP hh:mm:ss SP "GMT" + // asctime-date = wkday SP month dd SP hh:mm:ss SP yyyy + + static const char rfc1123_date[] = "%3s,;%2d;%3s;%4d;%2d:%2d:%2d;GMT"; + static const char rfc850_date[] = "%s,;%2d-%3s-%2d;%2d:%2d:%2d;GMT"; + static const char asctime_date[] = "%3s;%3s;%2d;%2d:%2d:%2d;%4d"; + + // Should also support other versions (such as from NNTP and SMTP) + // for robustness, but it should be clear how to extend this. + + struct tm tms; + char month[4]; + char weekday[10]; + + if (::sscanf(buf, rfc1123_date, + weekday, + &tms.tm_mday, + month, + &tms.tm_year, + &tms.tm_hour, + &tms.tm_min, + &tms.tm_sec) == 7) + ; + else if (::sscanf(buf, rfc850_date, + weekday, + &tms.tm_mday, month, &tms.tm_year, + &tms.tm_hour, &tms.tm_min, &tms.tm_sec) == 7) + { + weekday[3] = '\0'; + } + else if (::sscanf(buf, asctime_date, + weekday, + month, &tms.tm_mday, + &tms.tm_hour, &tms.tm_min, &tms.tm_sec, + &tms.tm_year) == 7) + { + } + + delete [] buf; + + tms.tm_year = HTTP_Helper::fixyear (tms.tm_year); + tms.tm_mon = HTTP_Helper::HTTP_month (month); + + if (tms.tm_mon == -1) + return (time_t) -1; + + // mktime is a Standard C function. + { + +#if !defined (ACE_HAS_REENTRANT_LIBC) + ACE_MT (ACE_Guard<ACE_SYNCH_MUTEX> g (HTTP_Helper::mutex_)); +#endif /* NOT ACE_HAS_REENTRANT_LIBC */ + + return ACE_OS::mktime (&tms); + } +} + +const char * +HTTP_Helper::HTTP_date (void) +{ + if (HTTP_Helper::date_string_ == 0) + { + ACE_MT (ACE_Guard<ACE_SYNCH_MUTEX> m (HTTP_Helper::mutex_)); + + if (HTTP_Helper::date_string_ == 0) + { + // 40 bytes is all I need. + ACE_NEW_RETURN (HTTP_Helper::date_string_, char[40], 0); + + if (!HTTP_Helper::HTTP_date (HTTP_Helper::date_string_)) + { + delete [] HTTP_Helper::date_string_; + HTTP_Helper::date_string_ = 0; + } + } + } + + return HTTP_Helper::date_string_; +} + +const char * +HTTP_Helper::HTTP_date (char *s) +{ + // Return the date-string formatted per HTTP standards. Time must + // be in UTC, so using the 'strftime' call (which obeys the locale) + // isn't correct. + static const char* months[] = {"Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec"}; + static const char* days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; + + time_t tloc; + struct tm tms; + char * date_string = s; + + if (ACE_OS::time (&tloc) != (time_t) -1 + && ACE_OS::gmtime_r (&tloc, &tms) != NULL) + { + ACE_OS::sprintf (date_string, + "%s, %2.2d %s %4.4d %2.2d:%2.2d:%2.2d GMT", + days[tms.tm_wday], tms.tm_mday, months[tms.tm_mon], + tms.tm_year + 1900, tms.tm_hour, tms.tm_min, tms.tm_sec); + } + else + date_string = 0; + + return date_string; +} + +int +HTTP_Helper::HTTP_month (const char *month) +{ + for (size_t i = 0; i < 12; i++) + if (ACE_OS::strcmp(month, HTTP_Helper::months_[i]) == 0) + return i; + + return -1; +} + +const char * +HTTP_Helper::HTTP_month (int month) +{ + if (month < 0 || month >= 12) + return 0; + + return HTTP_Helper::months_[month]; +} + +// Fix the path if it needs fixing/is fixable. + +char * +HTTP_Helper::HTTP_decode_string (char *path) +{ + // replace the percentcodes with the actual character + int i, j; + char percentcode[3]; + + for (i = j = 0; path[i] != '\0'; i++, j++) + { + if (path[i] == '%') + { + percentcode[0] = path[++i]; + percentcode[1] = path[++i]; + percentcode[2] = '\0'; + path[j] = (char) ACE_OS::strtol (percentcode, (char **) 0, 16); + } + else + path[j] = path[i]; + } + + path[j] = path[i]; + + return path; +} + +char * +HTTP_Helper::HTTP_decode_base64 (char *data) +{ + char inalphabet[256], decoder[256]; + + ACE_OS::memset (inalphabet, 0, sizeof (inalphabet)); + ACE_OS::memset (decoder, 0, sizeof (decoder)); + + for (int i = ACE_OS::strlen (HTTP_Helper::alphabet_) - 1; + i >= 0; + i--) + { + inalphabet[(unsigned int) HTTP_Helper::alphabet_[i]] = 1; + decoder[(unsigned int) HTTP_Helper::alphabet_[i]] = i; + } + + char *indata = data; + char *outdata = data; + + int bits = 0; + int c; + int char_count = 0; + int errors = 0; + + while ((c = *indata++) != '\0') + { + if (c == '=') + break; + if (c > 255 || ! inalphabet[c]) + continue; + bits += decoder[c]; + char_count++; + if (char_count == 4) + { + *outdata++ = (bits >> 16); + *outdata++ = ((bits >> 8) & 0xff); + *outdata++ = (bits & 0xff); + bits = 0; + char_count = 0; + } + else + bits <<= 6; + } + + if (c == '\0') + { + if (char_count) + { + ACE_DEBUG ((LM_DEBUG, + "base64 encoding incomplete: at least %d bits truncated\n", + ((4 - char_count) * 6))); + errors++; + } + } + else + { + // c == '=' + switch (char_count) + { + case 1: + ACE_DEBUG ((LM_DEBUG, + "base64 encoding incomplete: at least 2 bits missing\n")); + errors++; + break; + case 2: + *outdata++ = (bits >> 10); + break; + case 3: + *outdata++ = (bits >> 16); + *outdata++ = ((bits >> 8) & 0xff); + break; + } + } + *outdata = '\0'; + return errors ? 0 : data; +} + +char * +HTTP_Helper::HTTP_encode_base64 (char *data) +{ + char buf[BUFSIZ]; + int c; + int error; + int char_count = 0; + int bits = 0; + error = 0; + char *indata = data; + char *outdata = buf; + const unsigned char ASCII_MAX = ~0; + + while ((c = *indata++) != '\0') + { + if (c > (int)ASCII_MAX) + { + ACE_DEBUG ((LM_DEBUG, "encountered char > 255 (decimal %d)\n", c)); + error++; + break; + } + bits += c; + char_count++; + + if (char_count == 3) + { + *outdata++ = HTTP_Helper::alphabet_[bits >> 18]; + *outdata++ = HTTP_Helper::alphabet_[(bits >> 12) & 0x3f]; + *outdata++ = HTTP_Helper::alphabet_[(bits >> 6) & 0x3f]; + *outdata++ = HTTP_Helper::alphabet_[bits & 0x3f]; + bits = 0; + char_count = 0; + } + else + bits <<= 8; + } + + if (!error) + { + if (char_count != 0) + { + bits <<= 16 - (8 * char_count); + *outdata++ = HTTP_Helper::alphabet_[bits >> 18]; + *outdata++ = HTTP_Helper::alphabet_[(bits >> 12) & 0x3f]; + + if (char_count == 1) + { + *outdata++ = '='; + *outdata++ = '='; + } + else + { + *outdata++ = HTTP_Helper::alphabet_[(bits >> 6) & 0x3f]; + *outdata++ = '='; + } + } + *outdata = '\0'; + ACE_OS::strcpy (data, buf); + } + + return (error ? 0 : data); +} + +int +HTTP_Helper::fixyear (int year) +{ + // Fix the year 2000 problem + + if (year > 1000) + year -= 1900; + else if (year < 100) + { + struct tm tms; + time_t tloc; + + if (ACE_OS::time (&tloc) != (time_t) -1) + { + ACE_OS::gmtime_r (&tloc, &tms); + + if (tms.tm_year % 100 == year) + year = tms.tm_year; + + // The last two cases check boundary conditions, in case the + // year just changed at the moment we checked to see if we + // need to fix it. + if ((year+1) % 100 == tms.tm_year % 100) + year = tms.tm_year - 1; + + if (year == (tms.tm_year + 1) % 100) + year = tms.tm_year + 1; + + // What to do if none of the above? + } + } + + return year; +} + +const char ** +HTTP_Status_Code::instance (void) +{ + if (HTTP_Status_Code::instance_ == 0) + { + ACE_MT (ACE_Guard<ACE_SYNCH_MUTEX> g (lock_)); + + if (HTTP_Status_Code::instance_ == 0) + { + for (size_t i = 0; + i < HTTP_Status_Code::MAX_STATUS_CODE + 1; + i++) + { + switch (i) + { + case STATUS_OK: + HTTP_Status_Code::Reason[i] = "OK"; break; + case STATUS_CREATED: + HTTP_Status_Code::Reason[i] = "Created"; break; + case STATUS_ACCEPTED: + HTTP_Status_Code::Reason[i] = "Accepted"; break; + case STATUS_NO_CONTENT: + HTTP_Status_Code::Reason[i] = "No Content"; break; + case STATUS_MOVED_PERMANENTLY: + HTTP_Status_Code::Reason[i] = "Moved Permanently"; break; + case STATUS_MOVED_TEMPORARILY: + HTTP_Status_Code::Reason[i] = "Moved Temporarily"; break; + case STATUS_NOT_MODIFIED: + HTTP_Status_Code::Reason[i] = "Not Modified"; break; + case STATUS_BAD_REQUEST: + HTTP_Status_Code::Reason[i] = "Bad Request"; break; + case STATUS_UNAUTHORIZED: + HTTP_Status_Code::Reason[i] = "Unauthorized"; break; + case STATUS_FORBIDDEN: + HTTP_Status_Code::Reason[i] = "Forbidden"; break; + case STATUS_NOT_FOUND: + HTTP_Status_Code::Reason[i] = "Not Found"; break; + case STATUS_INTERNAL_SERVER_ERROR: + HTTP_Status_Code::Reason[i] = "Internal Server Error"; break; + case STATUS_NOT_IMPLEMENTED: + HTTP_Status_Code::Reason[i] = "Not Implemented"; break; + case STATUS_BAD_GATEWAY: + HTTP_Status_Code::Reason[i] = "Bad Gateway"; break; + case STATUS_SERVICE_UNAVAILABLE: + HTTP_Status_Code::Reason[i] = "Service Unavailable"; break; + default: + HTTP_Status_Code::Reason[i] = "Unknown"; + } + } + + HTTP_Status_Code::instance_ = 1; + } + + // GUARD released + } + + return HTTP_Status_Code::Reason; +} |