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(equal(multipart, multipart+sizeof(multipart), m_environment.contentType.begin()))
00117                         m_environment.parsePostsMultipart();
00118 
00119                      else if(equal(urlEncoded, urlEncoded+sizeof(urlEncoded), m_environment.contentType.begin()))
00120                         m_environment.parsePostsUrlEncoded();
00121 
00122                      else
00123                         throw Exceptions::UnknownContentType();
00124                   }
00125 
00126                   m_environment.clearPostBuffer();
00127                   state=OUT;
00128                   if(response())
00129                   {
00130                      complete();
00131                      return true;
00132                   }
00133                   break;
00134                }
00135 
00136                if(!m_environment.fillPostBuffer(body, header.getContentLength()))
00137                {
00138                   bigPostErrorHandler();
00139                   complete();
00140                   return true;
00141                }
00142 
00143                inHandler(header.getContentLength());
00144                break;
00145             }
00146 
00147             case ABORT_REQUEST:
00148             {
00149                return true;
00150             }
00151          }
00152       }
00153       else if(response())
00154       {
00155          complete();
00156          return true;
00157       }
00158    }
00159    catch(const std::exception& e)
00160    {
00161       errorHandler(e);
00162       complete();
00163       return true;
00164    }
00165    return false;
00166 }
00167 
00168 template void Fastcgipp::Request<char>::errorHandler(const std::exception& error);
00169 template void Fastcgipp::Request<wchar_t>::errorHandler(const std::exception& error);
00170 template<class charT> void Fastcgipp::Request<charT>::errorHandler(const std::exception& error)
00171 {
00172       out << \
00173 "Status: 500 Internal Server Error\n"\
00174 "Content-Type: text/html; charset=ISO-8859-1\r\n\r\n"\
00175 "<!DOCTYPE html>"\
00176 "<html lang='en'>"\
00177    "<head>"\
00178       "<title>500 Internal Server Error</title>"\
00179    "</head>"\
00180    "<body>"\
00181       "<h1>500 Internal Server Error</h1>"\
00182    "</body>"\
00183 "</html>";
00184 
00185       err << '"' << error.what() << '"' << " from \"http://" << environment().host << environment().requestUri << "\" with a " << environment().requestMethod << " request method.";
00186 }
00187 
00188 template void Fastcgipp::Request<char>::bigPostErrorHandler();
00189 template void Fastcgipp::Request<wchar_t>::bigPostErrorHandler();
00190 template<class charT> void Fastcgipp::Request<charT>::bigPostErrorHandler()
00191 {
00192       out << \
00193 "Status: 413 Request Entity Too Large\n"\
00194 "Content-Type: text/html; charset=ISO-8859-1\r\n\r\n"\
00195 "<!DOCTYPE html>"\
00196 "<html lang='en'>"\
00197    "<head>"\
00198       "<title>413 Request Entity Too Large</title>"\
00199    "</head>"\
00200    "<body>"\
00201       "<h1>413 Request Entity Too Large</h1>"\
00202    "</body>"\
00203 "</html>";
00204 }