fastcgi++
fcgistream.cpp
Go to the documentation of this file.
1 #include <cstring>
2 #include <algorithm>
3 #include <map>
4 #include <iterator>
5 #include <boost/iostreams/code_converter.hpp>
6 
8 #include "utf8_codecvt.hpp"
9 
10 template<typename charT> template<typename Sink> std::streamsize Fastcgipp::Fcgistream<charT>::Encoder::write(Sink& dest, const charT* s, std::streamsize n)
11 {
12  static std::map<charT, std::basic_string<charT> > htmlCharacters;
13  if(!htmlCharacters.size())
14  {
15  const char quot[]="&quot;";
16  std::copy(quot, quot+sizeof(quot)-1, std::back_inserter(htmlCharacters['"']));
17 
18  const char gt[]="&gt;";
19  std::copy(gt, gt+sizeof(gt)-1, std::back_inserter(htmlCharacters['>']));
20 
21  const char lt[]="&lt;";
22  std::copy(lt, lt+sizeof(lt)-1, std::back_inserter(htmlCharacters['<']));
23 
24  const char amp[]="&amp;";
25  std::copy(amp, amp+sizeof(amp)-1, std::back_inserter(htmlCharacters['&']));
26 
27  const char apos[]="&apos;";
28  std::copy(apos, apos+sizeof(apos)-1, std::back_inserter(htmlCharacters['\'']));
29  }
30 
31  static std::map<charT, std::basic_string<charT> > urlCharacters;
32  if(!urlCharacters.size())
33  {
34  const char exclaim[]="%21";
35  std::copy(exclaim, exclaim+sizeof(exclaim)-1, std::back_inserter(urlCharacters['!']));
36 
37  const char rightbrac[]="%5D";
38  std::copy(rightbrac, rightbrac+sizeof(rightbrac)-1, std::back_inserter(urlCharacters[']']));
39 
40  const char leftbrac[]="%5B";
41  std::copy(leftbrac, leftbrac+sizeof(leftbrac)-1, std::back_inserter(urlCharacters['[']));
42 
43  const char number[]="%23";
44  std::copy(number, number+sizeof(number)-1, std::back_inserter(urlCharacters['#']));
45 
46  const char question[]="%3F";
47  std::copy(question, question+sizeof(question)-1, std::back_inserter(urlCharacters['?']));
48 
49  const char slash[]="%2F";
50  std::copy(slash, slash+sizeof(slash)-1, std::back_inserter(urlCharacters['/']));
51 
52  const char comma[]="%2C";
53  std::copy(comma, comma+sizeof(comma)-1, std::back_inserter(urlCharacters[',']));
54 
55  const char money[]="%24";
56  std::copy(money, money+sizeof(money)-1, std::back_inserter(urlCharacters['$']));
57 
58  const char plus[]="%2B";
59  std::copy(plus, plus+sizeof(plus)-1, std::back_inserter(urlCharacters['+']));
60 
61  const char equal[]="%3D";
62  std::copy(equal, equal+sizeof(equal)-1, std::back_inserter(urlCharacters['=']));
63 
64  const char andsym[]="%26";
65  std::copy(andsym, andsym+sizeof(andsym)-1, std::back_inserter(urlCharacters['&']));
66 
67  const char at[]="%40";
68  std::copy(at, at+sizeof(at)-1, std::back_inserter(urlCharacters['@']));
69 
70  const char colon[]="%3A";
71  std::copy(colon, colon+sizeof(colon)-1, std::back_inserter(urlCharacters[':']));
72 
73  const char semi[]="%3B";
74  std::copy(semi, semi+sizeof(semi)-1, std::back_inserter(urlCharacters[';']));
75 
76  const char rightpar[]="%29";
77  std::copy(rightpar, rightpar+sizeof(rightpar)-1, std::back_inserter(urlCharacters[')']));
78 
79  const char leftpar[]="%28";
80  std::copy(leftpar, leftpar+sizeof(leftpar)-1, std::back_inserter(urlCharacters['(']));
81 
82  const char apos[]="%27";
83  std::copy(apos, apos+sizeof(apos)-1, std::back_inserter(urlCharacters['\'']));
84 
85  const char star[]="%2A";
86  std::copy(star, star+sizeof(star)-1, std::back_inserter(urlCharacters['*']));
87 
88  const char lt[]="%3C";
89  std::copy(lt, lt+sizeof(lt)-1, std::back_inserter(urlCharacters['<']));
90 
91  const char gt[]="%3E";
92  std::copy(gt, gt+sizeof(gt)-1, std::back_inserter(urlCharacters['>']));
93 
94  const char quot[]="%22";
95  std::copy(quot, quot+sizeof(quot)-1, std::back_inserter(urlCharacters['"']));
96 
97  const char space[]="%20";
98  std::copy(space, space+sizeof(space)-1, std::back_inserter(urlCharacters[' ']));
99 
100  const char percent[]="%25";
101  std::copy(percent, percent+sizeof(percent)-1, std::back_inserter(urlCharacters['%']));
102  }
103 
104  if(m_state==NONE)
105  boost::iostreams::write(dest, s, n);
106  else
107  {
108  std::map<charT, std::basic_string<charT> >* characters;
109  switch(m_state)
110  {
111  case HTML:
112  characters = &htmlCharacters;
113  break;
114  case URL:
115  characters = &urlCharacters;
116  break;
117  }
118 
119  const charT* start=s;
120  typename std::map<charT, std::basic_string<charT> >::const_iterator it;
121  for(const charT* i=s; i < s+n; ++i)
122  {
123  it=characters->find(*i);
124  if(it!=characters->end())
125  {
126  if(start<i) boost::iostreams::write(dest, start, start-i);
127  boost::iostreams::write(dest, it->second.data(), it->second.size());
128  start=i+1;
129  }
130  }
131  int size=s+n-start;
132  if(size) boost::iostreams::write(dest, start, size);
133  }
134  return n;
135 }
136 
137 std::streamsize Fastcgipp::FcgistreamSink::write(const char* s, std::streamsize n)
138 {
139  using namespace std;
140  using namespace Protocol;
141  const std::streamsize totalUsed=n;
142  while(1)
143  {{
144  if(!n)
145  break;
146 
147  int remainder=n%chunkSize;
148  size_t size=n+sizeof(Header)+(remainder?(chunkSize-remainder):remainder);
149  if(size>numeric_limits<uint16_t>::max()) size=numeric_limits<uint16_t>::max();
150  Block dataBlock(m_transceiver->requestWrite(size));
151  size=(dataBlock.size/chunkSize)*chunkSize;
152 
153  uint16_t contentLength=std::min(size-sizeof(Header), size_t(n));
154  memcpy(dataBlock.data+sizeof(Header), s, contentLength);
155 
156  s+=contentLength;
157  n-=contentLength;
158 
159  uint8_t contentPadding=chunkSize-contentLength%chunkSize;
160  if(contentPadding==8) contentPadding=0;
161 
162  Header& header=*(Header*)dataBlock.data;
163  header.setVersion(Protocol::version);
164  header.setType(m_type);
165  header.setRequestId(m_id.fcgiId);
166  header.setContentLength(contentLength);
167  header.setPaddingLength(contentPadding);
168 
169  m_transceiver->secureWrite(size, m_id, false);
170  }}
171  return totalUsed;
172 }
173 
174 void Fastcgipp::FcgistreamSink::dump(std::basic_istream<char>& stream)
175 {
176  const size_t bufferSize=32768;
177  char buffer[bufferSize];
178 
179  while(stream.good())
180  {
181  stream.read(buffer, bufferSize);
182  write(buffer, stream.gcount());
183  }
184 }
185 
186 template<typename T, typename toChar, typename fromChar> T& fixPush(boost::iostreams::filtering_stream<boost::iostreams::output, fromChar>& stream, const T& t, int buffer_size)
187 {
188  stream.push(t, buffer_size);
189  return *stream.template component<T>(stream.size()-1);
190 }
191 
192 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)
193 {
194  stream.push(boost::iostreams::code_converter<Fastcgipp::FcgistreamSink, utf8CodeCvt::utf8_codecvt_facet>(t, buffer_size));
195  return **stream.component<boost::iostreams::code_converter<Fastcgipp::FcgistreamSink, utf8CodeCvt::utf8_codecvt_facet> >(stream.size()-1);
196 }
197 
198 
201 template<typename charT> Fastcgipp::Fcgistream<charT>::Fcgistream():
202  m_encoder(fixPush<Encoder, charT, charT>(*this, Encoder(), 0)),
203  m_sink(fixPush<FcgistreamSink, char, charT>(*this, FcgistreamSink(), 8192))
204 {}
205 
206 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);
207 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);
208 template<class charT, class Traits> std::basic_ostream<charT, Traits>& Fastcgipp::operator<<(std::basic_ostream<charT, Traits>& os, const encoding& enc)
209 {
210  try
211  {
212  Fcgistream<charT>& stream(dynamic_cast<Fcgistream<charT>&>(os));
213  stream.setEncoding(enc.m_type);
214  }
215  catch(std::bad_cast& bc)
216  {
217  }
218 
219  return os;
220 }