fastcgi++
|
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[]="""; 00016 std::copy(quot, quot+sizeof(quot)-1, std::back_inserter(htmlCharacters['"'])); 00017 00018 const char gt[]=">"; 00019 std::copy(gt, gt+sizeof(gt)-1, std::back_inserter(htmlCharacters['>'])); 00020 00021 const char lt[]="<"; 00022 std::copy(lt, lt+sizeof(lt)-1, std::back_inserter(htmlCharacters['<'])); 00023 00024 const char amp[]="&"; 00025 std::copy(amp, amp+sizeof(amp)-1, std::back_inserter(htmlCharacters['&'])); 00026 00027 const char 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 }