fastcgi++
request.cpp
Go to the documentation of this file.
00001 
00002 /***************************************************************************
00003 * Copyright (C) 2007 Eddie Carle [eddie@erctech.org]                       *
00004 *                                                                          *
00005 * This file is part of fastcgi++.                                          *
00006 *                                                                          *
00007 * fastcgi++ is free software: you can redistribute it and/or modify it     *
00008 * under the terms of the GNU Lesser General Public License as  published   *
00009 * by the Free Software Foundation, either version 3 of the License, or (at *
00010 * your option) any later version.                                          *
00011 *                                                                          *
00012 * fastcgi++ is distributed in the hope that it will be useful, but WITHOUT *
00013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    *
00014 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public     *
00015 * License for more details.                                                *
00016 *                                                                          *
00017 * You should have received a copy of the GNU Lesser General Public License *
00018 * along with fastcgi++.  If not, see <http://www.gnu.org/licenses/>.       *
00019 ****************************************************************************/
00020 
00021 #include <fastcgi++/request.hpp>
00022 
00023 template void Fastcgipp::Request<char>::complete();
00024 template void Fastcgipp::Request<wchar_t>::complete();
00025 template<class charT> void Fastcgipp::Request<charT>::complete()
00026 {
00027    using namespace Protocol;
00028    out.flush();
00029    err.flush();
00030 
00031    Block buffer(transceiver->requestWrite(sizeof(Header)+sizeof(EndRequest)));
00032 
00033    Header& header=*(Header*)buffer.data;
00034    header.setVersion(Protocol::version);
00035    header.setType(END_REQUEST);
00036    header.setRequestId(id.fcgiId);
00037    header.setContentLength(sizeof(EndRequest));
00038    header.setPaddingLength(0);
00039    
00040    EndRequest& body=*(EndRequest*)(buffer.data+sizeof(Header));
00041    body.setAppStatus(0);
00042    body.setProtocolStatus(REQUEST_COMPLETE);
00043 
00044    transceiver->secureWrite(sizeof(Header)+sizeof(EndRequest), id, killCon);
00045 }
00046 
00047 template bool Fastcgipp::Request<char>::handler();
00048 template bool Fastcgipp::Request<wchar_t>::handler();
00049 template<class charT> bool Fastcgipp::Request<charT>::handler()
00050 {
00051    using namespace Protocol;
00052    using namespace std;
00053 
00054    try
00055    {
00056       if(!(role()==RESPONDER || role()==AUTHORIZER))
00057       {
00058          Block buffer(transceiver->requestWrite(sizeof(Header)+sizeof(EndRequest)));
00059          
00060          Header& header=*(Header*)buffer.data;
00061          header.setVersion(Protocol::version);
00062          header.setType(END_REQUEST);
00063          header.setRequestId(id.fcgiId);
00064          header.setContentLength(sizeof(EndRequest));
00065          header.setPaddingLength(0);
00066          
00067          EndRequest& body=*(EndRequest*)(buffer.data+sizeof(Header));
00068          body.setAppStatus(0);
00069          body.setProtocolStatus(UNKNOWN_ROLE);
00070 
00071          transceiver->secureWrite(sizeof(Header)+sizeof(EndRequest), id, killCon);
00072          return true;
00073       }
00074 
00075       {
00076          boost::lock_guard<boost::mutex> lock(messages);
00077          m_message=messages.front();
00078          messages.pop();
00079       }
00080 
00081       if(message().type==0)
00082       {
00083          const Header& header=*(Header*)message().data.get();
00084          const char* body=message().data.get()+sizeof(Header);
00085          switch(header.getType())
00086          {
00087             case PARAMS:
00088             {
00089                if(state!=PARAMS) throw Exceptions::RecordsOutOfOrder();
00090                if(header.getContentLength()==0) 
00091                {
00092                   if(m_maxPostSize && environment().contentLength > m_maxPostSize)
00093                   {
00094                      bigPostErrorHandler();
00095                      complete();
00096                      return true;
00097                   }
00098                   state=IN;
00099                   break;
00100                }
00101                m_environment.fill(body, header.getContentLength());
00102                break;
00103             }
00104 
00105             case IN:
00106             {
00107                if(state!=IN) throw Exceptions::RecordsOutOfOrder();
00108                if(header.getContentLength()==0)
00109                {
00110                   // Process POST data based on what our incoming content type is
00111                   if(m_environment.requestMethod == Http::HTTP_METHOD_POST)
00112                   {
00113                      const char multipart[] = "multipart/form-data";
00114                      const char urlEncoded[] = "application/x-www-form-urlencoded";
00115 
00116                      if(!inProcessor())
00117                      {
00118                         if(sizeof(multipart)-1 == m_environment.contentType.size() && equal(multipart, multipart+sizeof(multipart)-1, m_environment.contentType.begin()))
00119                            m_environment.parsePostsMultipart();
00120 
00121                         else if(sizeof(urlEncoded)-1 == m_environment.contentType.size() && equal(urlEncoded, urlEncoded+sizeof(urlEncoded)-1, m_environment.contentType.begin()))
00122                            m_environment.parsePostsUrlEncoded();
00123 
00124                         else
00125                            throw Exceptions::UnknownContentType();
00126                      }
00127                   }
00128 
00129                   m_environment.clearPostBuffer();
00130                   state=OUT;
00131                   if(response())
00132                   {
00133                      complete();
00134                      return true;
00135                   }
00136                   break;
00137                }
00138 
00139                if(!m_environment.fillPostBuffer(body, header.getContentLength()))
00140                {
00141                   bigPostErrorHandler();
00142                   complete();
00143                   return true;
00144                }
00145 
00146                inHandler(header.getContentLength());
00147                break;
00148             }
00149 
00150             case ABORT_REQUEST:
00151             {
00152                return true;
00153             }
00154          }
00155       }
00156       else if(response())
00157       {
00158          complete();
00159          return true;
00160       }
00161    }
00162    catch(const std::exception& e)
00163    {
00164       errorHandler(e);
00165       complete();
00166       return true;
00167    }
00168    return false;
00169 }
00170 
00171 template void Fastcgipp::Request<char>::errorHandler(const std::exception& error);
00172 template void Fastcgipp::Request<wchar_t>::errorHandler(const std::exception& error);
00173 template<class charT> void Fastcgipp::Request<charT>::errorHandler(const std::exception& error)
00174 {
00175       out << \
00176 "Status: 500 Internal Server Error\n"\
00177 "Content-Type: text/html; charset=ISO-8859-1\r\n\r\n"\
00178 "<!DOCTYPE html>"\
00179 "<html lang='en'>"\
00180    "<head>"\
00181       "<title>500 Internal Server Error</title>"\
00182    "</head>"\
00183    "<body>"\
00184       "<h1>500 Internal Server Error</h1>"\
00185    "</body>"\
00186 "</html>";
00187 
00188       err << '"' << error.what() << '"' << " from \"http://" << environment().host << environment().requestUri << "\" with a " << environment().requestMethod << " request method.";
00189 }
00190 
00191 template void Fastcgipp::Request<char>::bigPostErrorHandler();
00192 template void Fastcgipp::Request<wchar_t>::bigPostErrorHandler();
00193 template<class charT> void Fastcgipp::Request<charT>::bigPostErrorHandler()
00194 {
00195       out << \
00196 "Status: 413 Request Entity Too Large\n"\
00197 "Content-Type: text/html; charset=ISO-8859-1\r\n\r\n"\
00198 "<!DOCTYPE html>"\
00199 "<html lang='en'>"\
00200    "<head>"\
00201       "<title>413 Request Entity Too Large</title>"\
00202    "</head>"\
00203    "<body>"\
00204       "<h1>413 Request Entity Too Large</h1>"\
00205    "</body>"\
00206 "</html>";
00207 }