00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <algorithm>
00023
00024 #include <fastcgi++/http.hpp>
00025
00026 void Fastcgipp::Http::Address::assign(const char* start, const char* end)
00027 {
00028 data=0;
00029 for(int i=24; i>=0; i-=8)
00030 {
00031 char* point=(char*)memchr(start, '.', end-start);
00032 data|=atoi(start, end)<<i;
00033 if(!point || point+1>=end) break;
00034 start=point+1;
00035 }
00036 }
00037
00038 template std::basic_ostream<char, std::char_traits<char> >& Fastcgipp::Http::operator<<(std::basic_ostream<char, std::char_traits<char> >& os, const Address& address);
00039 template std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& Fastcgipp::Http::operator<<(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& os, const Address& address);
00040 template<class charT, class Traits> std::basic_ostream<charT, Traits>& Fastcgipp::Http::operator<<(std::basic_ostream<charT, Traits>& os, const Address& address)
00041 {
00042 using namespace std;
00043 if(!os.good()) return os;
00044
00045 try
00046 {
00047 typename basic_ostream<charT, Traits>::sentry opfx(os);
00048 if(opfx)
00049 {
00050 streamsize fieldWidth=os.width(0);
00051 charT buffer[20];
00052 charT* bufPtr=buffer;
00053 locale loc(os.getloc(), new num_put<charT, charT*>);
00054
00055 for(uint32_t mask=0xff000000, shift=24; mask!=0; mask>>=8, shift-=8)
00056 {
00057 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(bufPtr, os, os.fill(), static_cast<long unsigned int>((address.data&mask)>>shift));
00058 *bufPtr++=os.widen('.');
00059 }
00060 --bufPtr;
00061
00062 charT* ptr=buffer;
00063 ostreambuf_iterator<charT,Traits> sink(os);
00064 if(os.flags() & ios_base::left)
00065 for(int i=max(fieldWidth, bufPtr-buffer); i>0; i--)
00066 {
00067 if(ptr!=bufPtr) *sink++=*ptr++;
00068 else *sink++=os.fill();
00069 }
00070 else
00071 for(int i=fieldWidth-(bufPtr-buffer); ptr!=bufPtr;)
00072 {
00073 if(i>0) { *sink++=os.fill(); --i; }
00074 else *sink++=*ptr++;
00075 }
00076
00077 if(sink.failed()) os.setstate(ios_base::failbit);
00078 }
00079 }
00080 catch(bad_alloc&)
00081 {
00082 ios_base::iostate exception_mask = os.exceptions();
00083 os.exceptions(ios_base::goodbit);
00084 os.setstate(ios_base::badbit);
00085 os.exceptions(exception_mask);
00086 if(exception_mask & ios_base::badbit) throw;
00087 }
00088 catch(...)
00089 {
00090 ios_base::iostate exception_mask = os.exceptions();
00091 os.exceptions(ios_base::goodbit);
00092 os.setstate(ios_base::failbit);
00093 os.exceptions(exception_mask);
00094 if(exception_mask & ios_base::failbit) throw;
00095 }
00096 return os;
00097 }
00098
00099 template std::basic_istream<char, std::char_traits<char> >& Fastcgipp::Http::operator>>(std::basic_istream<char, std::char_traits<char> >& is, Address& address);
00100 template std::basic_istream<wchar_t, std::char_traits<wchar_t> >& Fastcgipp::Http::operator>>(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& is, Address& address);
00101 template<class charT, class Traits> std::basic_istream<charT, Traits>& Fastcgipp::Http::operator>>(std::basic_istream<charT, Traits>& is, Address& address)
00102 {
00103 using namespace std;
00104 if(!is.good()) return is;
00105
00106 ios_base::iostate err = ios::goodbit;
00107 try
00108 {
00109 typename basic_istream<charT, Traits>::sentry ipfx(is);
00110 if(ipfx)
00111 {
00112 uint32_t data=0;
00113 istreambuf_iterator<charT, Traits> it(is);
00114 for(int i=24; i>=0; i-=8, ++it)
00115 {
00116 uint32_t value;
00117 use_facet<num_get<charT, istreambuf_iterator<charT, Traits> > >(is.getloc()).get(it, istreambuf_iterator<charT, Traits>(), is, err, value);
00118 data|=value<<i;
00119 if(i && *it!=is.widen('.')) err = ios::failbit;
00120 }
00121 if(err == ios::goodbit) address=data;
00122 else is.setstate(err);
00123 }
00124 }
00125 catch(bad_alloc&)
00126 {
00127 ios_base::iostate exception_mask = is.exceptions();
00128 is.exceptions(ios_base::goodbit);
00129 is.setstate(ios_base::badbit);
00130 is.exceptions(exception_mask);
00131 if(exception_mask & ios_base::badbit) throw;
00132 }
00133 catch(...)
00134 {
00135 ios_base::iostate exception_mask = is.exceptions();
00136 is.exceptions(ios_base::goodbit);
00137 is.setstate(ios_base::failbit);
00138 is.exceptions(exception_mask);
00139 if(exception_mask & ios_base::failbit) throw;
00140 }
00141
00142 return is;
00143 }
00144
00145 template bool Fastcgipp::Http::parseXmlValue(const char* const name, const char* start, const char* end, std::basic_string<char>& string);
00146 template bool Fastcgipp::Http::parseXmlValue(const char* const name, const char* start, const char* end, std::basic_string<wchar_t>& string);
00147 template<class charT> bool Fastcgipp::Http::parseXmlValue(const char* const name, const char* start, const char* end, std::basic_string<charT>& string)
00148 {
00149 using namespace std;
00150
00151 size_t searchStringSize=strlen(name)+2;
00152 char* searchString=new char[searchStringSize+1];
00153 memcpy(searchString, name, searchStringSize-2);
00154 *(searchString+searchStringSize-2)='=';
00155 *(searchString+searchStringSize-1)='"';
00156 *(searchString+searchStringSize)='\0';
00157
00158 const char* valueStart=0;
00159
00160 for(; start<=end-searchStringSize; ++start)
00161 {
00162 if(valueStart && *start=='"') break;
00163 if(!memcmp(searchString, start, searchStringSize))
00164 {
00165 valueStart=start+searchStringSize;
00166 start+=searchStringSize-1;
00167 }
00168 }
00169
00170 delete [] searchString;
00171
00172 if(!valueStart)
00173 return false;
00174
00175 if(start-valueStart) charToString(valueStart, start-valueStart, string);
00176 return true;
00177 }
00178
00179 void Fastcgipp::Http::charToString(const char* data, size_t size, std::wstring& string)
00180 {
00181 const size_t bufferSize=512;
00182 wchar_t buffer[bufferSize];
00183 using namespace std;
00184
00185 if(size)
00186 {
00187 codecvt_base::result cr=codecvt_base::partial;
00188 while(cr==codecvt_base::partial)
00189 {{
00190 wchar_t* it;
00191 const char* tmpData;
00192 mbstate_t conversionState = mbstate_t();
00193 cr=use_facet<codecvt<wchar_t, char, mbstate_t> >(locale("en_US.UTF-8")).in(conversionState, data, data+size, tmpData, buffer, buffer+bufferSize, it);
00194 string.append(buffer, it);
00195 size-=tmpData-data;
00196 data=tmpData;
00197 }}
00198 if(cr==codecvt_base::error) throw Fastcgipp::Exceptions::FastcgiException("Error in code conversion of parameters");
00199 }
00200 }
00201
00202 int Fastcgipp::Http::atoi(const char* start, const char* end)
00203 {
00204 bool neg=false;
00205 if(*start=='-')
00206 {
00207 neg=false;
00208 ++start;
00209 }
00210 int result=0;
00211 for(; 0x30 <= *start && *start <= 0x39 && start<end; ++start)
00212 result=result*10+(*start&0x0f);
00213
00214 return neg?-result:result;
00215 }
00216
00217 int Fastcgipp::Http::percentEscapedToRealBytes(const char* source, char* destination, size_t size)
00218 {
00219 int i=0;
00220 char* start=destination;
00221 while(1)
00222 {
00223 if(*source=='%')
00224 {
00225 *destination=0;
00226 for(int shift=4; shift>=0; shift-=4)
00227 {
00228 if(++i==size) break;
00229 ++source;
00230 if((*source|0x20) >= 'a' && (*source|0x20) <= 'f')
00231 *destination|=(*source|0x20)-0x57<<shift;
00232 else if(*source >= '0' && *source <= '9')
00233 *destination|=(*source&0x0f)<<shift;
00234 }
00235 ++source;
00236 ++destination;
00237 if(++i==size) break;
00238 }
00239 else
00240 {
00241 *destination++=*source++;
00242 if(++i==size) break;
00243 }
00244 }
00245 return destination-start;
00246 }
00247
00248 template void Fastcgipp::Http::Session<char>::fill(const char* data, size_t size);
00249 template void Fastcgipp::Http::Session<wchar_t>::fill(const char* data, size_t size);
00250 template<class charT> void Fastcgipp::Http::Session<charT>::fill(const char* data, size_t size)
00251 {
00252 using namespace std;
00253 using namespace boost;
00254
00255 size_t nameSize;
00256 size_t valueSize;
00257 const char* name;
00258 const char* value;
00259 Protocol::processParamHeader(data, name, nameSize, value, valueSize);
00260
00261 if(name+nameSize+valueSize!=data+size) throw Fastcgipp::Exceptions::FastcgiException("Error decoding parameter packet.");
00262
00263 if(nameSize==9 && !memcmp(name, "HTTP_HOST", 9))
00264 charToString(value, valueSize, host);
00265 else if(nameSize==15 && !memcmp(name, "HTTP_USER_AGENT", 15))
00266 charToString(value, valueSize, userAgent);
00267 else if(nameSize==11 && !memcmp(name, "HTTP_ACCEPT", 11))
00268 charToString(value, valueSize, acceptContentTypes);
00269 else if(nameSize==20 && !memcmp(name, "HTTP_ACCEPT_LANGUAGE", 20))
00270 charToString(value, valueSize, acceptLanguages);
00271 else if(nameSize==19 && !memcmp(name, "HTTP_ACCEPT_CHARSET", 19))
00272 charToString(value, valueSize, acceptCharsets);
00273 else if(nameSize==12 && !memcmp(name, "HTTP_REFERER", 12) && valueSize)
00274 {
00275 scoped_array<char> buffer(new char[valueSize]);
00276 charToString(buffer.get(), percentEscapedToRealBytes(value, buffer.get(), valueSize), referer);
00277 }
00278 else if(nameSize==12 && !memcmp(name, "CONTENT_TYPE", 12))
00279 {
00280 const char* end=(char*)memchr(value, ';', valueSize);
00281 charToString(value, end?end-value:valueSize, contentType);
00282 if(end)
00283 {
00284 const char* start=(char*)memchr(end, '=', valueSize-(end-data));
00285 if(start)
00286 {
00287 boundarySize=valueSize-(++start-data);
00288 boundary.reset(new char[boundarySize]);
00289 memcpy(boundary.get(), start, boundarySize);
00290 }
00291 }
00292 }
00293 else if(nameSize==11 && !memcmp(name, "HTTP_COOKIE", 11))
00294 charToString(value, valueSize, cookies);
00295 else if(nameSize==13 && !memcmp(name, "DOCUMENT_ROOT", 13))
00296 charToString(value, valueSize, root);
00297 else if(nameSize==11 && !memcmp(name, "SCRIPT_NAME", 11))
00298 charToString(value, valueSize, scriptName);
00299 else if(nameSize==12 && !memcmp(name, "QUERY_STRING", 12) && valueSize)
00300 {
00301 scoped_array<char> buffer(new char[valueSize]);
00302 charToString(buffer.get(), percentEscapedToRealBytes(value, buffer.get(), valueSize), queryString);
00303 }
00304 else if(nameSize==15 && !memcmp(name, "HTTP_KEEP_ALIVE", 15))
00305 keepAlive=atoi(value, value+valueSize);
00306 else if(nameSize==14 && !memcmp(name, "CONTENT_LENGTH", 14))
00307 contentLength=atoi(value, value+valueSize);
00308 else if(nameSize==11 && !memcmp(name, "SERVER_ADDR", 11))
00309 serverAddress.assign(value, value+valueSize);
00310 else if(nameSize==11 && !memcmp(name, "REMOTE_ADDR", 11))
00311 remoteAddress.assign(value, value+valueSize);
00312 else if(nameSize==11 && !memcmp(name, "SERVER_PORT", 11))
00313 serverPort=atoi(value, value+valueSize);
00314 else if(nameSize==11 && !memcmp(name, "REMOTE_PORT", 11))
00315 remotePort=atoi(value, value+valueSize);
00316 else if(nameSize==22 && !memcmp(name, "HTTP_IF_MODIFIED_SINCE", 22))
00317 {
00318 stringstream dateStream;
00319 dateStream.write(value, valueSize);
00320 dateStream.imbue(locale(locale::classic(), new posix_time::time_input_facet("%a, %d %b %Y %H:%M:%S GMT")));
00321 dateStream >> ifModifiedSince;
00322 }
00323 else if(nameSize==18 && !memcmp(name, "HTTP_IF_NONE_MATCH", 18))
00324 etag=atoi(value, value+valueSize);
00325
00326
00327
00328
00329
00330
00331
00332
00333 }
00334
00335 template void Fastcgipp::Http::Session<char>::fillPosts(const char* data, size_t size);
00336 template void Fastcgipp::Http::Session<wchar_t>::fillPosts(const char* data, size_t size);
00337 template<class charT> void Fastcgipp::Http::Session<charT>::fillPosts(const char* data, size_t size)
00338 {
00339 using namespace std;
00340 while(1)
00341 {{
00342 size_t bufferSize=postBufferSize+size;
00343 char* buffer=new char[bufferSize];
00344 if(postBufferSize) memcpy(buffer, postBuffer.get(), postBufferSize);
00345 memcpy(buffer+postBufferSize, data, size);
00346 postBuffer.reset(buffer);
00347 postBufferSize=bufferSize;
00348
00349 const char* end=0;
00350 for(const char* i=buffer+boundarySize; i<buffer+bufferSize-boundarySize; ++i)
00351 if(!memcmp(i, boundary.get(), boundarySize))
00352 {
00353 end=i;
00354 break;
00355 }
00356
00357 if(!end)
00358 return;
00359
00360 end-=4;
00361 const char* start=buffer+boundarySize+2;
00362 const char* bodyStart=start;
00363 for(; bodyStart<=end-4; ++bodyStart)
00364 if(!memcmp(bodyStart, "\r\n\r\n", 4)) break;
00365 bodyStart+=4;
00366 basic_string<charT> name;
00367
00368 if(parseXmlValue("name", start, bodyStart, name))
00369 {
00370 Post<charT>& thePost=posts[name];
00371 if(parseXmlValue("filename", start, bodyStart, thePost.value))
00372 {
00373 thePost.type=Post<charT>::file;
00374 thePost.size=end-bodyStart;
00375 if(thePost.size)
00376 {
00377 thePost.data.reset(new char[thePost.size]);
00378 memcpy(thePost.data.get(), bodyStart, thePost.size);
00379 }
00380 }
00381 else
00382 {
00383 thePost.type=Post<charT>::form;
00384 charToString(bodyStart, end-bodyStart, thePost.value);
00385 }
00386 }
00387
00388 bufferSize=bufferSize-(end-buffer+2);
00389 if(!bufferSize)
00390 {
00391 postBuffer.reset();
00392 return;
00393 }
00394 buffer=new char[bufferSize];
00395 memcpy(buffer, end+2, bufferSize);
00396 postBuffer.reset(buffer);
00397 postBufferSize=bufferSize;
00398 size=0;
00399 }}
00400 }
00401
00402