fastcgi++
fcgistream.cpp
Go to the documentation of this file.
00001 #include <cstring>
00002 #include <algorithm>
00003 #include <map>
00004 #include <iterator>
00005 #include <boost/iostreams/code_converter.hpp>
00006 
00007 #include "fastcgi++/fcgistream.hpp"
00008 #include "utf8_codecvt.hpp"
00009 
00010 template<typename charT> template<typename Sink> std::streamsize Fastcgipp::Fcgistream<charT>::Encoder::write(Sink& dest, const charT* s, std::streamsize n)
00011 {
00012    static std::map<charT, std::basic_string<charT> > htmlCharacters;
00013    if(!htmlCharacters.size())
00014    {
00015       const char quot[]="&quot;";
00016       std::copy(quot, quot+sizeof(quot)-1, std::back_inserter(htmlCharacters['"']));
00017 
00018       const char gt[]="&gt;";
00019       std::copy(gt, gt+sizeof(gt)-1, std::back_inserter(htmlCharacters['>']));
00020 
00021       const char lt[]="&lt;";
00022       std::copy(lt, lt+sizeof(lt)-1, std::back_inserter(htmlCharacters['<']));
00023 
00024       const char amp[]="&amp;";
00025       std::copy(amp, amp+sizeof(amp)-1, std::back_inserter(htmlCharacters['&']));
00026 
00027       const char apos[]="&apos;";
00028       std::copy(apos, apos+sizeof(apos)-1, std::back_inserter(htmlCharacters['\'']));
00029    }
00030 
00031    static std::map<charT, std::basic_string<charT> > urlCharacters;
00032    if(!urlCharacters.size())
00033    {
00034       const char exclaim[]="%21";
00035       std::copy(exclaim, exclaim+sizeof(exclaim)-1, std::back_inserter(urlCharacters['!']));
00036 
00037       const char rightbrac[]="%5D";
00038       std::copy(rightbrac, rightbrac+sizeof(rightbrac)-1, std::back_inserter(urlCharacters[']']));
00039 
00040       const char leftbrac[]="%5B";
00041       std::copy(leftbrac, leftbrac+sizeof(leftbrac)-1, std::back_inserter(urlCharacters['[']));
00042 
00043       const char number[]="%23";
00044       std::copy(number, number+sizeof(number)-1, std::back_inserter(urlCharacters['#']));
00045 
00046       const char question[]="%3F";
00047       std::copy(question, question+sizeof(question)-1, std::back_inserter(urlCharacters['?']));
00048 
00049       const char slash[]="%2F";
00050       std::copy(slash, slash+sizeof(slash)-1, std::back_inserter(urlCharacters['/']));
00051 
00052       const char comma[]="%2C";
00053       std::copy(comma, comma+sizeof(comma)-1, std::back_inserter(urlCharacters[',']));
00054 
00055       const char money[]="%24";
00056       std::copy(money, money+sizeof(money)-1, std::back_inserter(urlCharacters['$']));
00057 
00058       const char plus[]="%2B";
00059       std::copy(plus, plus+sizeof(plus)-1, std::back_inserter(urlCharacters['+']));
00060 
00061       const char equal[]="%3D";
00062       std::copy(equal, equal+sizeof(equal)-1, std::back_inserter(urlCharacters['=']));
00063 
00064       const char andsym[]="%26";
00065       std::copy(andsym, andsym+sizeof(andsym)-1, std::back_inserter(urlCharacters['&']));
00066 
00067       const char at[]="%40";
00068       std::copy(at, at+sizeof(at)-1, std::back_inserter(urlCharacters['@']));
00069 
00070       const char colon[]="%3A";
00071       std::copy(colon, colon+sizeof(colon)-1, std::back_inserter(urlCharacters[':']));
00072 
00073       const char semi[]="%3B";
00074       std::copy(semi, semi+sizeof(semi)-1, std::back_inserter(urlCharacters[';']));
00075 
00076       const char rightpar[]="%29";
00077       std::copy(rightpar, rightpar+sizeof(rightpar)-1, std::back_inserter(urlCharacters[')']));
00078 
00079       const char leftpar[]="%28";
00080       std::copy(leftpar, leftpar+sizeof(leftpar)-1, std::back_inserter(urlCharacters['(']));
00081 
00082       const char apos[]="%27";
00083       std::copy(apos, apos+sizeof(apos)-1, std::back_inserter(urlCharacters['\'']));
00084 
00085       const char star[]="%2A";
00086       std::copy(star, star+sizeof(star)-1, std::back_inserter(urlCharacters['*']));
00087 
00088       const char lt[]="%3C";
00089       std::copy(lt, lt+sizeof(lt)-1, std::back_inserter(urlCharacters['<']));
00090 
00091       const char gt[]="%3E";
00092       std::copy(gt, gt+sizeof(gt)-1, std::back_inserter(urlCharacters['>']));
00093 
00094       const char quot[]="%22";
00095       std::copy(quot, quot+sizeof(quot)-1, std::back_inserter(urlCharacters['"']));
00096 
00097       const char space[]="%20";
00098       std::copy(space, space+sizeof(space)-1, std::back_inserter(urlCharacters[' ']));
00099 
00100       const char percent[]="%25";
00101       std::copy(percent, percent+sizeof(percent)-1, std::back_inserter(urlCharacters['%']));
00102    }
00103 
00104    if(m_state==NONE)
00105       boost::iostreams::write(dest, s, n);
00106    else
00107    {
00108       std::map<charT, std::basic_string<charT> >* characters;
00109       switch(m_state)
00110       {
00111          case HTML:
00112             characters = &htmlCharacters;
00113             break;
00114          case URL:
00115             characters = &urlCharacters;
00116             break;
00117       }
00118 
00119       const charT* start=s;
00120       typename std::map<charT, std::basic_string<charT> >::const_iterator it;
00121       for(const charT* i=s; i < s+n; ++i)
00122       {
00123          it=characters->find(*i);
00124          if(it!=characters->end())
00125          {
00126             if(start<i) boost::iostreams::write(dest, start, start-i);
00127             boost::iostreams::write(dest, it->second.data(), it->second.size());
00128             start=i+1;
00129          }
00130       }
00131       int size=s+n-start;
00132       if(size) boost::iostreams::write(dest, start, size);
00133    }
00134    return n;
00135 }
00136 
00137 std::streamsize Fastcgipp::FcgistreamSink::write(const char* s, std::streamsize n)
00138 {
00139    using namespace std;
00140    using namespace Protocol;
00141    const std::streamsize totalUsed=n;
00142    while(1)
00143    {{
00144       if(!n)
00145          break;
00146 
00147       int remainder=n%chunkSize;
00148       size_t size=n+sizeof(Header)+(remainder?(chunkSize-remainder):remainder);
00149       if(size>numeric_limits<uint16_t>::max()) size=numeric_limits<uint16_t>::max();
00150       Block dataBlock(m_transceiver->requestWrite(size));
00151       size=(dataBlock.size/chunkSize)*chunkSize;
00152 
00153       uint16_t contentLength=std::min(size-sizeof(Header), size_t(n));
00154       memcpy(dataBlock.data+sizeof(Header), s, contentLength);
00155 
00156       s+=contentLength;
00157       n-=contentLength;
00158 
00159       uint8_t contentPadding=chunkSize-contentLength%chunkSize;
00160       if(contentPadding==8) contentPadding=0;
00161       
00162       Header& header=*(Header*)dataBlock.data;
00163       header.setVersion(Protocol::version);
00164       header.setType(m_type);
00165       header.setRequestId(m_id.fcgiId);
00166       header.setContentLength(contentLength);
00167       header.setPaddingLength(contentPadding);
00168 
00169       m_transceiver->secureWrite(size, m_id, false);  
00170    }}
00171    return totalUsed;
00172 }
00173 
00174 void Fastcgipp::FcgistreamSink::dump(std::basic_istream<char>& stream)
00175 {
00176    const size_t bufferSize=32768;
00177    char buffer[bufferSize];
00178 
00179    while(stream.good())
00180    {
00181       stream.read(buffer, bufferSize);
00182       write(buffer, stream.gcount());
00183    }
00184 }
00185 
00186 template<typename T, typename toChar, typename fromChar> T& fixPush(boost::iostreams::filtering_stream<boost::iostreams::output, fromChar>& stream, const T& t, int buffer_size)
00187 {
00188    stream.push(t, buffer_size);
00189    return *stream.template component<T>(stream.size()-1);
00190 }
00191 
00192 template<> Fastcgipp::FcgistreamSink& fixPush<Fastcgipp::FcgistreamSink, char, wchar_t>(boost::iostreams::filtering_stream<boost::iostreams::output, wchar_t>& stream, const Fastcgipp::FcgistreamSink& t, int buffer_size)
00193 {
00194    stream.push(boost::iostreams::code_converter<Fastcgipp::FcgistreamSink, utf8CodeCvt::utf8_codecvt_facet>(t, buffer_size));
00195    return **stream.component<boost::iostreams::code_converter<Fastcgipp::FcgistreamSink, utf8CodeCvt::utf8_codecvt_facet> >(stream.size()-1);
00196 }
00197 
00198 
00199 template Fastcgipp::Fcgistream<char>::Fcgistream();
00200 template Fastcgipp::Fcgistream<wchar_t>::Fcgistream();
00201 template<typename charT> Fastcgipp::Fcgistream<charT>::Fcgistream():
00202    m_encoder(fixPush<Encoder, charT, charT>(*this, Encoder(), 0)),
00203    m_sink(fixPush<FcgistreamSink, char, charT>(*this, FcgistreamSink(), 8192))
00204 {}
00205 
00206 template std::basic_ostream<char, std::char_traits<char> >& Fastcgipp::operator<< <char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >& os, const encoding& enc);
00207 template std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& Fastcgipp::operator<< <wchar_t, std::char_traits<wchar_t> >(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& os, const encoding& enc);
00208 template<class charT, class Traits> std::basic_ostream<charT, Traits>& Fastcgipp::operator<<(std::basic_ostream<charT, Traits>& os, const encoding& enc)
00209 {
00210    try
00211    {
00212       Fcgistream<charT>& stream(dynamic_cast<Fcgistream<charT>&>(os));
00213       stream.setEncoding(enc.m_type);
00214    }
00215    catch(std::bad_cast& bc)
00216    {
00217    }
00218 
00219    return os;
00220 }