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