00001 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 #ifdef _MSC_VER
00031 #pragma warning(disable:4786)
00032 #endif
00033 #include "HttpdCookies.h"
00034 #include "HttpdForm.h"
00035 #include "MemFile.h"
00036 #include "HttpdSocket.h"
00037 #include "Base64.h"
00038 
00039 
00040 #ifdef SOCKETS_NAMESPACE
00041 namespace SOCKETS_NAMESPACE {
00042 #endif
00043 
00044 #define TMPSIZE 10000
00045 
00046 
00047 
00048 int HttpdSocket::m_request_count = 0;
00049 std::string HttpdSocket::m_start = "";
00050 
00051 
00052 HttpdSocket::HttpdSocket(ISocketHandler& h)
00053 :HTTPSocket(h)
00054 ,m_content_length(0)
00055 ,m_file(NULL)
00056 ,m_received(0)
00057 ,m_request_id(++m_request_count)
00058 ,m_cookies(NULL)
00059 ,m_form(NULL)
00060 {
00061         m_http_date = datetime2httpdate(GetDate());
00062         if (!m_start.size())
00063                 m_start = m_http_date;
00064 }
00065 
00066 
00067 HttpdSocket::~HttpdSocket()
00068 {
00069         if (m_file)
00070         {
00071                 delete m_file;
00072         }
00073         if (m_cookies)
00074                 delete m_cookies;
00075         if (m_form)
00076                 delete m_form;
00077 }
00078 
00079 
00080 void HttpdSocket::OnFirst()
00081 {
00082 }
00083 
00084 
00085 void HttpdSocket::OnHeader(const std::string& key,const std::string& value)
00086 {
00087         if (!strcasecmp(key.c_str(),"content-length"))
00088         {
00089                 m_content_length = atoi(value.c_str());
00090                 m_content_length_str = value;
00091         }
00092         else
00093         if (!strcasecmp(key.c_str(),"cookie"))
00094         {
00095                 m_http_cookie = value;
00096         }
00097         else
00098         if (!strcasecmp(key.c_str(),"content-type"))
00099         {
00100                 m_content_type = value;
00101         }
00102         else
00103         if (!strcasecmp(key.c_str(),"if-modified-since"))
00104         {
00105                 m_if_modified_since = value;
00106         }
00107 }
00108 
00109 
00110 void HttpdSocket::OnHeaderComplete()
00111 {
00112         m_cookies = new HttpdCookies(m_http_cookie);
00113 
00114         if (GetMethod() == "GET")
00115         {
00116                 Utility::SetEnv("QUERY_STRING", GetQueryString());
00117         }
00118         Utility::SetEnv("REQUEST_METHOD", GetMethod());
00119         Utility::SetEnv("HTTP_COOKIE", m_http_cookie);
00120         Utility::SetEnv("CONTENT_TYPE", m_content_type);
00121         Utility::SetEnv("CONTENT_LENGTH", m_content_length_str);
00122         if (GetMethod() == "POST")
00123         {
00124                 m_file = new MemFile;
00125         }
00126         else
00127         if (GetMethod() == "GET")
00128         {
00129                 m_form = new HttpdForm(GetQueryString(), GetQueryString().size() );
00130                 AddResponseHeader("Date", datetime2httpdate(GetDate()) );
00131                 if (GetUri() == "/image")
00132                 {
00133                         Send64(Utility::Logo, "image/png");
00134                 }
00135                 else
00136                 {
00137                         Exec();
00138                 }
00139                 Reset(); 
00140         }
00141         else
00142         {
00143                 AddResponseHeader("Date", GetHttpDate());
00144                 AddResponseHeader("Connection", "close");
00145                 SetStatus("405");
00146                 SetStatusText("Method not allowed");
00147                 SendResponse();
00148         }
00149 }
00150 
00151 
00152 void HttpdSocket::OnData(const char *p,size_t l)
00153 {
00154         if (m_file)
00155         {
00156                 m_file -> fwrite(p,1,l);
00157         }
00158         m_received += l;
00159         if (m_received >= m_content_length && m_content_length)
00160         {
00161                 
00162                 if (m_file && !m_form)
00163                 {
00164                         m_form = new HttpdForm(m_file, m_content_type, m_content_length);
00165                         AddResponseHeader("Date", datetime2httpdate(GetDate()) );
00166                         if (GetUri() == "/image")
00167                         {
00168                                 Send64(Utility::Logo, "image/png");
00169                         }
00170                         else
00171                         {
00172                                 Exec();
00173                         }
00174                         Reset(); 
00175                 }
00176         }
00177 }
00178 
00179 
00180 void HttpdSocket::Send64(const std::string& str64, const std::string& type)
00181 {
00182         Base64 bb;
00183 
00184         if (!strcasecmp(m_start.c_str(), m_if_modified_since.c_str()))
00185         {
00186                 SetStatus("304");
00187                 SetStatusText("Not Modified");
00188                 SendResponse();
00189         }
00190         else
00191         {
00192                 size_t len = bb.decode_length(str64);
00193                 unsigned char *buf = new unsigned char[len];
00194 
00195                 SetStatus("200");
00196                 SetStatusText("OK");
00197 
00198                 AddResponseHeader("Content-length", Utility::l2string( (long)len) );
00199                 AddResponseHeader("Content-type", type );
00200                 AddResponseHeader("Last-modified", m_start);
00201                 SendResponse();
00202 
00203                 bb.decode(str64, buf, len);
00204                 SendBuf( (char *)buf, len);
00205                 delete[] buf;
00206         }
00207 }
00208 
00209 
00210 std::string HttpdSocket::datetime2httpdate(const std::string& dt)
00211 {
00212         struct tm tp;
00213         time_t t;
00214         const char *days[] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
00215         const char *months[] = { "Jan","Feb","Mar","Apr","May","Jun",
00216                            "Jul","Aug","Sep","Oct","Nov","Dec" };
00217         int i;
00218         char s[40];
00219 
00220 
00221 
00222         if (dt.size() == 19) 
00223         {
00224                 tp.tm_year = atoi(dt.substr(0,4).c_str()) - 1900;
00225                 i = atoi(dt.substr(5,2).c_str()) - 1;
00226                 tp.tm_mon = i >= 0 ? i : 0;
00227                 tp.tm_mday = atoi(dt.substr(8,2).c_str());
00228                 tp.tm_hour = atoi(dt.substr(11,2).c_str());
00229                 tp.tm_min = atoi(dt.substr(14,2).c_str());
00230                 tp.tm_sec = atoi(dt.substr(17,2).c_str());
00231                 tp.tm_wday = 0;
00232                 tp.tm_yday = 0;
00233                 tp.tm_isdst = 0;
00234                 t = mktime(&tp);
00235                 if (t == -1)
00236                 {
00237                         Handler().LogError(this, "datetime2httpdate", 0, "mktime() failed");
00238                 }
00239 
00240                 snprintf(s,sizeof(s),"%s, %02d %s %d %02d:%02d:%02d GMT",
00241                  days[tp.tm_wday],
00242                  tp.tm_mday,
00243                  months[tp.tm_mon],
00244                  tp.tm_year + 1900,
00245                  tp.tm_hour,tp.tm_min,tp.tm_sec);
00246         } 
00247         else
00248         {
00249                 *s = 0;
00250         }
00251         return s;
00252 }
00253 
00254 
00255 std::string HttpdSocket::GetDate()
00256 {
00257         time_t t = time(NULL);
00258         char slask[40]; 
00259 #ifdef __CYGWIN__
00260         struct tm *tp = localtime(&t);
00261         snprintf(slask,sizeof(slask),"%d-%02d-%02d %02d:%02d:%02d",
00262                 tp -> tm_year + 1900,
00263                 tp -> tm_mon + 1,
00264                 tp -> tm_mday,
00265                 tp -> tm_hour,tp -> tm_min,tp -> tm_sec);
00266 #else
00267         struct tm tp;
00268 #if defined( _WIN32) && !defined(__CYGWIN__)
00269         localtime_s(&tp, &t);
00270 #else
00271         localtime_r(&t, &tp);
00272 #endif
00273         snprintf(slask,sizeof(slask),"%d-%02d-%02d %02d:%02d:%02d",
00274                 tp.tm_year + 1900,
00275                 tp.tm_mon + 1,
00276                 tp.tm_mday,
00277                 tp.tm_hour,tp.tm_min,tp.tm_sec);
00278 #endif
00279         return slask;
00280 }
00281 
00282 
00283 void HttpdSocket::Reset()
00284 {
00285         HTTPSocket::Reset();
00286         m_content_length = 0;
00287         if (m_file)
00288         {
00289                 delete m_file;
00290                 m_file = NULL;
00291         }
00292         m_received = 0;
00293         m_request_id = ++m_request_count;
00294         if (m_cookies)
00295                 delete m_cookies;
00296         m_cookies = NULL;
00297         if (m_form)
00298                 delete m_form;
00299         m_form = NULL;
00300 }
00301 
00302 
00303 const std::string& HttpdSocket::GetHttpDate() const
00304 {
00305         return m_http_date; 
00306 }
00307 
00308 
00309 HttpdCookies *HttpdSocket::GetCookies()
00310 {
00311         return m_cookies; 
00312 }
00313 
00314 
00315 const HttpdForm *HttpdSocket::GetForm() const
00316 {
00317         return m_form; 
00318 }
00319 
00320 
00321 
00322 #ifdef SOCKETS_NAMESPACE
00323 }
00324 #endif
00325 
00326