• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

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 
00022 #include <fastcgi++/request.hpp>
00023 #include "utf8_codecvt.hpp"
00024 
00025 namespace Fastcgipp
00026 {
00027    template<class charT> inline std::locale makeLocale(std::locale& loc)
00028    {
00029       return loc;
00030    }
00031    
00032    template<> std::locale inline makeLocale<wchar_t>(std::locale& loc)
00033    {
00034       return std::locale(loc, new utf8CodeCvt::utf8_codecvt_facet);
00035    }
00036 }
00037 
00038 template int Fastcgipp::Fcgistream<char, std::char_traits<char> >::Fcgibuf::emptyBuffer();
00039 template int Fastcgipp::Fcgistream<wchar_t, std::char_traits<wchar_t> >::Fcgibuf::emptyBuffer();
00040 template <class charT, class traits>
00041 int Fastcgipp::Fcgistream<charT, traits>::Fcgibuf::emptyBuffer()
00042 {
00043    using namespace std;
00044    using namespace Protocol;
00045    char_type const* pStreamPos=this->pbase();
00046    while(1)
00047    {{
00048       size_t count=this->pptr()-pStreamPos;
00049       size_t wantedSize=count*sizeof(char_type)+dumpSize;
00050       if(!wantedSize)
00051          break;
00052 
00053       int remainder=wantedSize%chunkSize;
00054       wantedSize+=sizeof(Header)+(remainder?(chunkSize-remainder):remainder);
00055       if(wantedSize>numeric_limits<uint16_t>::max()) wantedSize=numeric_limits<uint16_t>::max();
00056       Block dataBlock(transceiver->requestWrite(wantedSize));
00057       dataBlock.size=(dataBlock.size/chunkSize)*chunkSize;
00058 
00059       mbstate_t cs = mbstate_t();
00060       char* toNext=dataBlock.data+sizeof(Header);
00061 
00062       locale loc=this->getloc();
00063       if(count)
00064       {
00065          if(sizeof(char_type)!=sizeof(char))
00066          {
00067             if(use_facet<codecvt<char_type, char, mbstate_t> >(loc).out(cs, pStreamPos, this->pptr(), pStreamPos, toNext, dataBlock.data+dataBlock.size, toNext)==codecvt_base::error)
00068             {
00069                pbump(-(this->pptr()-this->pbase()));
00070                dumpSize=0;
00071                dumpPtr=0;
00072                throw Exceptions::CodeCvt();
00073             }
00074          }
00075          else
00076          {
00077             size_t cnt=min(dataBlock.size-sizeof(Header), count);
00078             memcpy(dataBlock.data+sizeof(Header), pStreamPos, cnt);
00079             pStreamPos+=cnt;
00080             toNext+=cnt;
00081          }
00082       }
00083 
00084       size_t dumpedSize=min(dumpSize, static_cast<size_t>(dataBlock.data+dataBlock.size-toNext));
00085       memcpy(toNext, dumpPtr, dumpedSize);
00086       dumpPtr+=dumpedSize;
00087       dumpSize-=dumpedSize;
00088       uint16_t contentLength=toNext-dataBlock.data+dumpedSize-sizeof(Header);
00089       uint8_t contentRemainder=contentLength%chunkSize;
00090       
00091       Header& header=*(Header*)dataBlock.data;
00092       header.setVersion(Protocol::version);
00093       header.setType(type);
00094       header.setRequestId(id.fcgiId);
00095       header.setContentLength(contentLength);
00096       header.setPaddingLength(contentRemainder?(chunkSize-contentRemainder):contentRemainder);
00097 
00098       transceiver->secureWrite(sizeof(Header)+contentLength+header.getPaddingLength(), id, false); 
00099    }}
00100    pbump(-(this->pptr()-this->pbase()));
00101    return 0;
00102 }
00103 
00104 template std::streamsize Fastcgipp::Fcgistream<char, std::char_traits<char> >::Fcgibuf::xsputn(const char_type *s, std::streamsize n);
00105 template std::streamsize Fastcgipp::Fcgistream<wchar_t, std::char_traits<wchar_t> >::Fcgibuf::xsputn(const char_type *s, std::streamsize n);
00106 template <class charT, class traits>
00107 std::streamsize Fastcgipp::Fcgistream<charT, traits>::Fcgibuf::xsputn(const char_type *s, std::streamsize n)
00108 {
00109    std::streamsize remainder=n;
00110    while(remainder)
00111    {
00112       std::streamsize actual=std::min(remainder, this->epptr()-this->pptr());
00113       std::memcpy(this->pptr(), s, actual*sizeof(char_type));
00114       this->pbump(actual);
00115       remainder-=actual;
00116       if(remainder)
00117       {
00118          s+=actual;
00119          emptyBuffer();
00120       }
00121    }
00122 
00123    return n;
00124 }
00125 
00126 template Fastcgipp::Fcgistream<char, std::char_traits<char> >::Fcgibuf::int_type Fastcgipp::Fcgistream<char, std::char_traits<char> >::Fcgibuf::overflow(Fastcgipp::Fcgistream<char, std::char_traits<char> >::Fcgibuf::int_type c = traits_type::eof());
00127 template Fastcgipp::Fcgistream<wchar_t, std::char_traits<wchar_t> >::Fcgibuf::int_type Fastcgipp::Fcgistream<wchar_t, std::char_traits<wchar_t> >::Fcgibuf::overflow(Fastcgipp::Fcgistream<wchar_t, std::char_traits<wchar_t> >::Fcgibuf::int_type c = traits_type::eof());
00128 template <class charT, class traits>
00129 typename Fastcgipp::Fcgistream<charT, traits>::Fcgibuf::int_type Fastcgipp::Fcgistream<charT, traits>::Fcgibuf::overflow(Fastcgipp::Fcgistream<charT, traits>::Fcgibuf::int_type c)
00130 {
00131    if(emptyBuffer() < 0)
00132       return traits_type::eof();
00133    if(!traits_type::eq_int_type(c, traits_type::eof()))
00134       return sputc(c);
00135    else
00136       return traits_type::not_eof(c);
00137 }
00138 
00139 template void Fastcgipp::Request<char>::complete();
00140 template void Fastcgipp::Request<wchar_t>::complete();
00141 template<class charT> void Fastcgipp::Request<charT>::complete()
00142 {
00143    using namespace Protocol;
00144    out.flush();
00145    err.flush();
00146 
00147    Block buffer(transceiver->requestWrite(sizeof(Header)+sizeof(EndRequest)));
00148 
00149    Header& header=*(Header*)buffer.data;
00150    header.setVersion(Protocol::version);
00151    header.setType(END_REQUEST);
00152    header.setRequestId(id.fcgiId);
00153    header.setContentLength(sizeof(EndRequest));
00154    header.setPaddingLength(0);
00155    
00156    EndRequest& body=*(EndRequest*)(buffer.data+sizeof(Header));
00157    body.setAppStatus(0);
00158    body.setProtocolStatus(REQUEST_COMPLETE);
00159 
00160    transceiver->secureWrite(sizeof(Header)+sizeof(EndRequest), id, killCon);
00161 }
00162 
00163 template void Fastcgipp::Fcgistream<char, std::char_traits<char> >::dump(std::basic_istream<char>& stream);
00164 template void Fastcgipp::Fcgistream<wchar_t, std::char_traits<wchar_t> >::dump(std::basic_istream<char>& stream);
00165 template<class charT, class traits > void Fastcgipp::Fcgistream<charT, traits>::dump(std::basic_istream<char>& stream)
00166 {
00167    const size_t bufferSize=32768;
00168    char buffer[bufferSize];
00169 
00170    while(stream.good())
00171    {
00172       stream.read(buffer, bufferSize);
00173       dump(buffer, stream.gcount());
00174    }
00175 }
00176 
00177 template bool Fastcgipp::Request<char>::handler();
00178 template bool Fastcgipp::Request<wchar_t>::handler();
00179 template<class charT> bool Fastcgipp::Request<charT>::handler()
00180 {
00181    using namespace Protocol;
00182    using namespace std;
00183 
00184    try
00185    {
00186       if(!(role()==RESPONDER || role()==AUTHORIZER))
00187       {
00188          Block buffer(transceiver->requestWrite(sizeof(Header)+sizeof(EndRequest)));
00189          
00190          Header& header=*(Header*)buffer.data;
00191          header.setVersion(Protocol::version);
00192          header.setType(END_REQUEST);
00193          header.setRequestId(id.fcgiId);
00194          header.setContentLength(sizeof(EndRequest));
00195          header.setPaddingLength(0);
00196          
00197          EndRequest& body=*(EndRequest*)(buffer.data+sizeof(Header));
00198          body.setAppStatus(0);
00199          body.setProtocolStatus(UNKNOWN_ROLE);
00200 
00201          transceiver->secureWrite(sizeof(Header)+sizeof(EndRequest), id, killCon);
00202          return true;
00203       }
00204 
00205       {
00206          boost::lock_guard<boost::mutex> lock(messages);
00207          m_message=messages.front();
00208          messages.pop();
00209       }
00210 
00211       if(message().type==0)
00212       {
00213          const Header& header=*(Header*)message().data.get();
00214          const char* body=message().data.get()+sizeof(Header);
00215          switch(header.getType())
00216          {
00217             case PARAMS:
00218             {
00219                if(state!=PARAMS) throw Exceptions::RecordsOutOfOrder();
00220                if(header.getContentLength()==0) 
00221                {
00222                   state=IN;
00223                   break;
00224                }
00225                m_environment.fill(body, header.getContentLength());
00226                break;
00227             }
00228 
00229             case IN:
00230             {
00231                if(state!=IN) throw Exceptions::RecordsOutOfOrder();
00232                if(header.getContentLength()==0)
00233                {
00234                   m_environment.clearPostBuffer();
00235                   state=OUT;
00236                   if(response())
00237                   {
00238                      complete();
00239                      return true;
00240                   }
00241                   break;
00242                }
00243 
00244                // Process POST data based on what our incoming content type is
00245                {
00246                   const char multipart[] = "multipart/form-data";
00247                   const char urlEncoded[] = "application/x-www-form-urlencoded";
00248 
00249                   if(equal(multipart, multipart+sizeof(multipart), m_environment.contentType.begin()))
00250                      m_environment.fillPostsMultipart(body, header.getContentLength());
00251 
00252                   else if(equal(urlEncoded, urlEncoded+sizeof(urlEncoded), m_environment.contentType.begin()))
00253                      m_environment.fillPostsUrlEncoded(body, header.getContentLength());
00254 
00255                   else
00256                      throw Exceptions::UnknownContentType();
00257                }
00258 
00259                inHandler(header.getContentLength());
00260                break;
00261             }
00262 
00263             case ABORT_REQUEST:
00264             {
00265                return true;
00266             }
00267          }
00268       }
00269       else if(response())
00270       {
00271          complete();
00272          return true;
00273       }
00274    }
00275    catch(const std::exception& e)
00276    {
00277       errorHandler(e);
00278       complete();
00279       return true;
00280    }
00281    return false;
00282 }
00283 
00284 template void Fastcgipp::Request<char>::setloc(std::locale loc_);
00285 template void Fastcgipp::Request<wchar_t>::setloc(std::locale loc_);
00286 template<class charT> void Fastcgipp::Request<charT>::setloc(std::locale loc_)
00287 {
00288    loc=makeLocale<charT>(loc_);
00289    out.imbue(loc);
00290    err.imbue(loc);
00291 }
00292 
00293 template void Fastcgipp::Request<char>::errorHandler(const std::exception& error);
00294 template void Fastcgipp::Request<wchar_t>::errorHandler(const std::exception& error);
00295 template<class charT> void Fastcgipp::Request<charT>::errorHandler(const std::exception& error)
00296 {
00297       out << \
00298 "Status: 500 Internal Server Error\n"\
00299 "Content-Type: text/html; charset=ISO-8859-1\r\n\r\n"\
00300 "<!DOCTYPE html>"\
00301 "<html lang='en'>"\
00302    "<head>"\
00303       "<title>500 Internal Server Error</title>"\
00304    "</head>"\
00305    "<body>"\
00306       "<h1>500 Internal Server Error</h1>"\
00307    "</body>"\
00308 "</html>";
00309 
00310       err << '"' << error.what() << '"' << " from \"http://" << environment().host << environment().requestUri << "\" with a " << environment().requestMethod << " request method.";
00311 }

Generated on Fri Jan 21 2011 12:29:32 for fastcgi++ by  doxygen 1.7.2