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 #include <boost/date_time/posix_time/posix_time.hpp>
00024
00025 #include <fastcgi++/http.hpp>
00026
00027 #include "utf8_codecvt.hpp"
00028
00029 void Fastcgipp::Http::Address::assign(const char* start, const char* end)
00030 {
00031 data=0;
00032 for(int i=24; i>=0; i-=8)
00033 {
00034 char* point=(char*)memchr(start, '.', end-start);
00035 data|=atoi(start, end)<<i;
00036 if(!point || point+1>=end) break;
00037 start=point+1;
00038 }
00039 }
00040
00041 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);
00042 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);
00043 template<class charT, class Traits> std::basic_ostream<charT, Traits>& Fastcgipp::Http::operator<<(std::basic_ostream<charT, Traits>& os, const Address& address)
00044 {
00045 using namespace std;
00046 if(!os.good()) return os;
00047
00048 try
00049 {
00050 typename basic_ostream<charT, Traits>::sentry opfx(os);
00051 if(opfx)
00052 {
00053 streamsize fieldWidth=os.width(0);
00054 charT buffer[20];
00055 charT* bufPtr=buffer;
00056 locale loc(os.getloc(), new num_put<charT, charT*>);
00057
00058 for(uint32_t mask=0xff000000, shift=24; mask!=0; mask>>=8, shift-=8)
00059 {
00060 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(bufPtr, os, os.fill(), static_cast<long unsigned int>((address.data&mask)>>shift));
00061 *bufPtr++=os.widen('.');
00062 }
00063 --bufPtr;
00064
00065 charT* ptr=buffer;
00066 ostreambuf_iterator<charT,Traits> sink(os);
00067 if(os.flags() & ios_base::left)
00068 for(int i=max(fieldWidth, bufPtr-buffer); i>0; i--)
00069 {
00070 if(ptr!=bufPtr) *sink++=*ptr++;
00071 else *sink++=os.fill();
00072 }
00073 else
00074 for(int i=fieldWidth-(bufPtr-buffer); ptr!=bufPtr;)
00075 {
00076 if(i>0) { *sink++=os.fill(); --i; }
00077 else *sink++=*ptr++;
00078 }
00079
00080 if(sink.failed()) os.setstate(ios_base::failbit);
00081 }
00082 }
00083 catch(bad_alloc&)
00084 {
00085 ios_base::iostate exception_mask = os.exceptions();
00086 os.exceptions(ios_base::goodbit);
00087 os.setstate(ios_base::badbit);
00088 os.exceptions(exception_mask);
00089 if(exception_mask & ios_base::badbit) throw;
00090 }
00091 catch(...)
00092 {
00093 ios_base::iostate exception_mask = os.exceptions();
00094 os.exceptions(ios_base::goodbit);
00095 os.setstate(ios_base::failbit);
00096 os.exceptions(exception_mask);
00097 if(exception_mask & ios_base::failbit) throw;
00098 }
00099 return os;
00100 }
00101
00102 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);
00103 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);
00104 template<class charT, class Traits> std::basic_istream<charT, Traits>& Fastcgipp::Http::operator>>(std::basic_istream<charT, Traits>& is, Address& address)
00105 {
00106 using namespace std;
00107 if(!is.good()) return is;
00108
00109 ios_base::iostate err = ios::goodbit;
00110 try
00111 {
00112 typename basic_istream<charT, Traits>::sentry ipfx(is);
00113 if(ipfx)
00114 {
00115 uint32_t data=0;
00116 istreambuf_iterator<charT, Traits> it(is);
00117 for(int i=24; i>=0; i-=8, ++it)
00118 {
00119 uint32_t value;
00120 use_facet<num_get<charT, istreambuf_iterator<charT, Traits> > >(is.getloc()).get(it, istreambuf_iterator<charT, Traits>(), is, err, value);
00121 data|=value<<i;
00122 if(i && *it!=is.widen('.')) err = ios::failbit;
00123 }
00124 if(err == ios::goodbit) address=data;
00125 else is.setstate(err);
00126 }
00127 }
00128 catch(bad_alloc&)
00129 {
00130 ios_base::iostate exception_mask = is.exceptions();
00131 is.exceptions(ios_base::goodbit);
00132 is.setstate(ios_base::badbit);
00133 is.exceptions(exception_mask);
00134 if(exception_mask & ios_base::badbit) throw;
00135 }
00136 catch(...)
00137 {
00138 ios_base::iostate exception_mask = is.exceptions();
00139 is.exceptions(ios_base::goodbit);
00140 is.setstate(ios_base::failbit);
00141 is.exceptions(exception_mask);
00142 if(exception_mask & ios_base::failbit) throw;
00143 }
00144
00145 return is;
00146 }
00147
00148 void Fastcgipp::Http::charToString(const char* data, size_t size, std::wstring& string)
00149 {
00150 const size_t bufferSize=512;
00151 wchar_t buffer[bufferSize];
00152 using namespace std;
00153
00154 if(size)
00155 {
00156 codecvt_base::result cr=codecvt_base::partial;
00157 while(cr==codecvt_base::partial)
00158 {{
00159 wchar_t* it;
00160 const char* tmpData;
00161 mbstate_t conversionState = mbstate_t();
00162 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);
00163 string.append(buffer, it);
00164 size-=tmpData-data;
00165 data=tmpData;
00166 }}
00167 if(cr==codecvt_base::error) throw Exceptions::CodeCvt();
00168 }
00169 }
00170
00171 int Fastcgipp::Http::atoi(const char* start, const char* end)
00172 {
00173 bool neg=false;
00174 if(*start=='-')
00175 {
00176 neg=true;
00177 ++start;
00178 }
00179 int result=0;
00180 for(; 0x30 <= *start && *start <= 0x39 && start<end; ++start)
00181 result=result*10+(*start&0x0f);
00182
00183 return neg?-result:result;
00184 }
00185
00186 size_t Fastcgipp::Http::percentEscapedToRealBytes(const char* source, char* destination, size_t size)
00187 {
00188 if (size < 1) return 0;
00189
00190 unsigned int i=0;
00191 char* start=destination;
00192 while(1)
00193 {
00194 if(*source=='%')
00195 {
00196 *destination=0;
00197 for(int shift=4; shift>=0; shift-=4)
00198 {
00199 if(++i==size) break;
00200 ++source;
00201 if((*source|0x20) >= 'a' && (*source|0x20) <= 'f')
00202 *destination|=((*source|0x20)-0x57)<<shift;
00203 else if(*source >= '0' && *source <= '9')
00204 *destination|=(*source&0x0f)<<shift;
00205 }
00206 ++source;
00207 ++destination;
00208 }
00209 else if(*source=='+')
00210 {
00211 *destination++=' ';
00212 ++source;
00213 }
00214 else
00215 *destination++=*source++;
00216
00217 if(++i==size) break;
00218 }
00219 return destination-start;
00220 }
00221
00222 template void Fastcgipp::Http::Environment<char>::fill(const char* data, size_t size);
00223 template void Fastcgipp::Http::Environment<wchar_t>::fill(const char* data, size_t size);
00224 template<class charT> void Fastcgipp::Http::Environment<charT>::fill(const char* data, size_t size)
00225 {
00226 using namespace std;
00227 using namespace boost;
00228
00229 while(size)
00230 {{
00231 size_t nameSize;
00232 size_t valueSize;
00233 const char* name;
00234 const char* value;
00235 Protocol::processParamHeader(data, size, name, nameSize, value, valueSize);
00236 size-=value-data+valueSize;
00237 data=value+valueSize;
00238
00239 switch(nameSize)
00240 {
00241 case 9:
00242 if(!memcmp(name, "HTTP_HOST", 9))
00243 charToString(value, valueSize, host);
00244 else if(!memcmp(name, "PATH_INFO", 9))
00245 charToString(value, valueSize, pathInfo);
00246 break;
00247 case 11:
00248 if(!memcmp(name, "HTTP_ACCEPT", 11))
00249 charToString(value, valueSize, acceptContentTypes);
00250 else if(!memcmp(name, "HTTP_COOKIE", 11))
00251 decodeUrlEncoded(value, valueSize, cookies, ';');
00252 else if(!memcmp(name, "SERVER_ADDR", 11))
00253 serverAddress.assign(value, value+valueSize);
00254 else if(!memcmp(name, "REMOTE_ADDR", 11))
00255 remoteAddress.assign(value, value+valueSize);
00256 else if(!memcmp(name, "SERVER_PORT", 11))
00257 serverPort=atoi(value, value+valueSize);
00258 else if(!memcmp(name, "REMOTE_PORT", 11))
00259 remotePort=atoi(value, value+valueSize);
00260 else if(!memcmp(name, "SCRIPT_NAME", 11))
00261 charToString(value, valueSize, scriptName);
00262 else if(!memcmp(name, "REQUEST_URI", 11))
00263 charToString(value, valueSize, requestUri);
00264 break;
00265 case 12:
00266 if(!memcmp(name, "HTTP_REFERER", 12) && valueSize)
00267 charToString(value, valueSize, referer);
00268 else if(!memcmp(name, "CONTENT_TYPE", 12))
00269 {
00270 const char* end=(char*)memchr(value, ';', valueSize);
00271 charToString(value, end?end-value:valueSize, contentType);
00272 if(end)
00273 {
00274 const char* start=(char*)memchr(end, '=', valueSize-(end-data));
00275 if(start)
00276 {
00277 boundarySize=valueSize-(++start-value);
00278 boundary.reset(new char[boundarySize]);
00279 memcpy(boundary.get(), start, boundarySize);
00280 }
00281 }
00282 }
00283 else if(!memcmp(name, "QUERY_STRING", 12) && valueSize)
00284 decodeUrlEncoded(value, valueSize, gets);
00285 break;
00286 case 13:
00287 if(!memcmp(name, "DOCUMENT_ROOT", 13))
00288 charToString(value, valueSize, root);
00289 break;
00290 case 14:
00291 if(!memcmp(name, "REQUEST_METHOD", 14))
00292 {
00293 requestMethod = HTTP_METHOD_ERROR;
00294 switch(valueSize)
00295 {
00296 case 3:
00297 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_GET], 3)) requestMethod = HTTP_METHOD_GET;
00298 else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_PUT], 3)) requestMethod = HTTP_METHOD_PUT;
00299 break;
00300 case 4:
00301 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_HEAD], 4)) requestMethod = HTTP_METHOD_HEAD;
00302 else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_POST], 4)) requestMethod = HTTP_METHOD_POST;
00303 break;
00304 case 5:
00305 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_TRACE], 5)) requestMethod = HTTP_METHOD_TRACE;
00306 break;
00307 case 6:
00308 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_DELETE], 6)) requestMethod = HTTP_METHOD_DELETE;
00309 break;
00310 case 7:
00311 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_OPTIONS], 7)) requestMethod = HTTP_METHOD_OPTIONS;
00312 else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_OPTIONS], 7)) requestMethod = HTTP_METHOD_CONNECT;
00313 break;
00314 }
00315 }
00316 else if(!memcmp(name, "CONTENT_LENGTH", 14))
00317 contentLength=atoi(value, value+valueSize);
00318 break;
00319 case 15:
00320 if(!memcmp(name, "HTTP_USER_AGENT", 15))
00321 charToString(value, valueSize, userAgent);
00322 else if(!memcmp(name, "HTTP_KEEP_ALIVE", 15))
00323 keepAlive=atoi(value, value+valueSize);
00324 break;
00325 case 18:
00326 if(!memcmp(name, "HTTP_IF_NONE_MATCH", 18))
00327 etag=atoi(value, value+valueSize);
00328 break;
00329 case 19:
00330 if(!memcmp(name, "HTTP_ACCEPT_CHARSET", 19))
00331 charToString(value, valueSize, acceptCharsets);
00332 break;
00333 case 20:
00334 if(!memcmp(name, "HTTP_ACCEPT_LANGUAGE", 20))
00335 charToString(value, valueSize, acceptLanguages);
00336 break;
00337 case 22:
00338 if(!memcmp(name, "HTTP_IF_MODIFIED_SINCE", 22))
00339 {
00340 stringstream dateStream;
00341 dateStream.write(value, valueSize);
00342 dateStream.imbue(locale(locale::classic(), new posix_time::time_input_facet("%a, %d %b %Y %H:%M:%S GMT")));
00343 dateStream >> ifModifiedSince;
00344 }
00345 break;
00346 }
00347 }}
00348 }
00349
00350 template void Fastcgipp::Http::Environment<char>::fillPostsMultipart(const char* data, size_t size);
00351 template void Fastcgipp::Http::Environment<wchar_t>::fillPostsMultipart(const char* data, size_t size);
00352 template<class charT> void Fastcgipp::Http::Environment<charT>::fillPostsMultipart(const char* data, size_t size)
00353 {
00354 using namespace std;
00355 while(1)
00356 {{
00357 size_t bufferSize=postBufferSize+size;
00358 char* buffer=new char[bufferSize];
00359 if(postBufferSize) memcpy(buffer, postBuffer.get(), postBufferSize);
00360 memcpy(buffer+postBufferSize, data, size);
00361 postBuffer.reset(buffer);
00362 postBufferSize=bufferSize;
00363
00364 const char* end=0;
00365 for(const char* i=buffer+boundarySize; i<buffer+bufferSize-boundarySize; ++i)
00366 if(!memcmp(i, boundary.get(), boundarySize))
00367 {
00368 end=i;
00369 break;
00370 }
00371
00372 if(!end)
00373 return;
00374
00375 end-=4;
00376 const char* start=buffer+boundarySize+2;
00377 const char* bodyStart=start;
00378 for(; bodyStart<=end-4; ++bodyStart)
00379 if(!memcmp(bodyStart, "\r\n\r\n", 4)) break;
00380 bodyStart+=4;
00381
00382
00383 const char* contentTypeStart;
00384 ssize_t contentTypeSize=-1;
00385 const char* nameStart;
00386 ssize_t nameSize=-1;
00387 const char* filenameStart;
00388 ssize_t filenameSize=-1;
00389
00390 {
00391 const char cContentType[] = "Content-Type: ";
00392 const char cContentDisposition[] = "Content-Disposition: ";
00393 const char cFilename[] = "filename=\"";
00394 const char cName[] = "name=\"";
00395
00396 enum ParseState { TITLE, CONTENT_DISPOSITION, FILENAME, NAME, CONTENT_TYPE, SKIP } parseState=TITLE;
00397 for(const char* i=start; i<bodyStart; ++i)
00398 {
00399 switch(*i)
00400 {
00401 case '\n':
00402 case '\r':
00403 {
00404 if(parseState==CONTENT_TYPE)
00405 contentTypeSize=i-contentTypeStart;
00406 parseState=TITLE;
00407 break;
00408 }
00409
00410 case '"':
00411 {
00412 if(parseState==FILENAME)
00413 {
00414 filenameSize=i-filenameStart;
00415 parseState=CONTENT_DISPOSITION;
00416 }
00417 else if(parseState==NAME)
00418 {
00419 nameSize=i-nameStart;
00420 parseState=CONTENT_DISPOSITION;
00421 }
00422 break;
00423 }
00424
00425 default:
00426 {
00427 if(parseState==TITLE)
00428 {
00429 if(sizeof(cContentType)-1 <= bodyStart-i && !memcmp(cContentType, i, sizeof(cContentType)-1))
00430 {
00431 parseState=CONTENT_TYPE;
00432 i += sizeof(cContentType)-1;
00433 contentTypeStart=i;
00434 }
00435 else if(sizeof(cContentDisposition)-1 <= bodyStart-i && !memcmp(cContentDisposition, i, sizeof(cContentDisposition)-1))
00436 {
00437 parseState=CONTENT_DISPOSITION;
00438 i += sizeof(cContentDisposition)-1;
00439 }
00440 else
00441 parseState=SKIP;
00442 }
00443 else if(parseState==CONTENT_DISPOSITION)
00444 {
00445 if(sizeof(cFilename)-1 <= bodyStart-i && !memcmp(cFilename, i, sizeof(cFilename)-1))
00446 {
00447 parseState=FILENAME;
00448 i += sizeof(cFilename)-1;
00449 filenameStart=i;
00450 }
00451 else if(sizeof(cName)-1 <= bodyStart-i && !memcmp(cName, i, sizeof(cName)-1))
00452 {
00453 parseState=NAME;
00454 i += sizeof(cName)-1;
00455 nameStart=i;
00456 }
00457 }
00458 break;
00459 }
00460 }
00461 }
00462 }
00463
00464
00465 if(nameSize != -1)
00466 {
00467 basic_string<charT> name;
00468 charToString(nameStart, nameSize, name);
00469
00470 Post<charT>& thePost=posts[name];
00471 if(contentTypeSize != -1)
00472 {
00473 thePost.type=Post<charT>::file;
00474 charToString(contentTypeStart, contentTypeSize, thePost.contentType);
00475 if(filenameSize != -1) charToString(filenameStart, filenameSize, thePost.filename);
00476 thePost.size=end-bodyStart;
00477 if(thePost.size)
00478 {
00479 thePost.data.reset(new char[thePost.size]);
00480 memcpy(thePost.data.get(), bodyStart, thePost.size);
00481 }
00482 }
00483 else
00484 {
00485 thePost.type=Post<charT>::form;
00486 charToString(bodyStart, end-bodyStart, thePost.value);
00487 }
00488 }
00489
00490 bufferSize=bufferSize-(end-buffer+2);
00491 if(!bufferSize)
00492 {
00493 postBuffer.reset();
00494 return;
00495 }
00496 buffer=new char[bufferSize];
00497 memcpy(buffer, end+2, bufferSize);
00498 postBuffer.reset(buffer);
00499 postBufferSize=bufferSize;
00500 size=0;
00501 }}
00502 }
00503
00504 template void Fastcgipp::Http::Environment<char>::fillPostsUrlEncoded(const char* data, size_t size);
00505 template void Fastcgipp::Http::Environment<wchar_t>::fillPostsUrlEncoded(const char* data, size_t size);
00506 template<class charT> void Fastcgipp::Http::Environment<charT>::fillPostsUrlEncoded(const char* data, size_t size)
00507 {
00508 using namespace std;
00509
00510 if(!postBuffer.get() && size)
00511 {
00512 postBuffer.reset(new char[contentLength]);
00513 postBufferSize=0;
00514 }
00515
00516
00517 size=min(size, contentLength-postBufferSize);
00518
00519 memcpy(postBuffer.get()+postBufferSize, data, size);
00520 postBufferSize+=size;
00521
00522 if(postBufferSize != contentLength)
00523 return;
00524
00525 char* nameStart=postBuffer.get();
00526 size_t nameSize;
00527 char* valueStart=0;
00528 size_t valueSize;
00529 for(char* i=postBuffer.get(); i<=postBuffer.get()+postBufferSize; ++i)
00530 {
00531 if(*i == '=' && nameStart && !valueStart)
00532 {
00533 nameSize=percentEscapedToRealBytes(nameStart, nameStart, i-nameStart);
00534 valueStart=i+1;
00535 }
00536 else if( (i==postBuffer.get()+postBufferSize || *i == '&') && nameStart && valueStart)
00537 {
00538 valueSize=percentEscapedToRealBytes(valueStart, valueStart, i-valueStart);
00539
00540 basic_string<charT> name;
00541 charToString(nameStart, nameSize, name);
00542 nameStart=i+1;
00543 Post<charT>& thePost=posts[name];
00544 thePost.type=Post<charT>::form;
00545 charToString(valueStart, valueSize, thePost.value);
00546 valueStart=0;
00547 }
00548 }
00549 }
00550
00551 bool Fastcgipp::Http::SessionId::seeded=false;
00552
00553 Fastcgipp::Http::SessionId::SessionId()
00554 {
00555 if(!seeded)
00556 {
00557 std::srand(boost::posix_time::microsec_clock::universal_time().time_of_day().fractional_seconds());
00558 seeded=true;
00559 }
00560
00561 for(char* i=data; i<data+size; ++i)
00562 *i=char(rand()%256);
00563 timestamp = boost::posix_time::second_clock::universal_time();
00564 }
00565
00566 template const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=<const char>(const char* data_);
00567 template const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=<const wchar_t>(const wchar_t* data_);
00568 template<class charT> const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=(charT* data_)
00569 {
00570 std::memset(data, 0, size);
00571 base64Decode(data_, data_+size*4/3, data);
00572 timestamp = boost::posix_time::second_clock::universal_time();
00573 return *this;
00574 }
00575
00576 template void Fastcgipp::Http::decodeUrlEncoded<char>(const char* data, size_t size, std::map<std::basic_string<char>, std::basic_string<char> >& output, const char fieldSeperator);
00577 template void Fastcgipp::Http::decodeUrlEncoded<wchar_t>(const char* data, size_t size, std::map<std::basic_string<wchar_t>, std::basic_string<wchar_t> >& output, const char fieldSeperator);
00578 template<class charT> void Fastcgipp::Http::decodeUrlEncoded(const char* data, size_t size, std::map<std::basic_string<charT>, std::basic_string<charT> >& output, const char fieldSeperator)
00579 {
00580 using namespace std;
00581
00582 boost::scoped_array<char> buffer(new char[size]);
00583 memcpy(buffer.get(), data, size);
00584
00585 char* nameStart=buffer.get();
00586 size_t nameSize;
00587 char* valueStart=0;
00588 size_t valueSize;
00589 for(char* i=buffer.get(); i<=buffer.get()+size; ++i)
00590 {
00591 if(*i == ' ' && nameStart && !valueStart)
00592 ++nameStart;
00593
00594 else if(*i == '=' && nameStart && !valueStart)
00595 {
00596 nameSize=percentEscapedToRealBytes(nameStart, nameStart, i-nameStart);
00597 valueStart=i+1;
00598 }
00599 else if( (i==buffer.get()+size || *i == fieldSeperator) && nameStart && valueStart)
00600 {
00601 valueSize=percentEscapedToRealBytes(valueStart, valueStart, i-valueStart);
00602
00603 basic_string<charT> name;
00604 charToString(nameStart, nameSize, name);
00605 nameStart=i+1;
00606 basic_string<charT>& value=output[name];
00607 charToString(valueStart, valueSize, value);
00608 valueStart=0;
00609 }
00610 }
00611 }
00612
00613 const char Fastcgipp::Http::base64Characters[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00614 const char* Fastcgipp::Http::requestMethodLabels[]= {
00615 "ERROR",
00616 "HEAD",
00617 "GET",
00618 "POST",
00619 "PUT",
00620 "DELETE",
00621 "TRACE",
00622 "OPTIONS",
00623 "CONNECT"
00624 };
00625
00626 template const std::basic_string<char>& Fastcgipp::Http::Environment<char>::findCookie(const char* key) const;
00627 template const std::basic_string<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findCookie(const wchar_t* key) const;
00628 template<class charT> const std::basic_string<charT>& Fastcgipp::Http::Environment<charT>::findCookie(const charT* key) const
00629 {
00630 static const std::basic_string<charT> emptyString;
00631 typename Cookies::const_iterator it=cookies.find(key);
00632 if(it==cookies.end())
00633 return emptyString;
00634 else
00635 return it->second;
00636 }
00637
00638 template const std::basic_string<char>& Fastcgipp::Http::Environment<char>::findGet(const char* key) const;
00639 template const std::basic_string<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findGet(const wchar_t* key) const;
00640 template<class charT> const std::basic_string<charT>& Fastcgipp::Http::Environment<charT>::findGet(const charT* key) const
00641 {
00642 static const std::basic_string<charT> emptyString;
00643 typename Gets::const_iterator it=gets.find(key);
00644 if(it==gets.end())
00645 return emptyString;
00646 else
00647 return it->second;
00648 }
00649
00650 template const Fastcgipp::Http::Post<char>& Fastcgipp::Http::Environment<char>::findPost(const char* key) const;
00651 template const Fastcgipp::Http::Post<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findPost(const wchar_t* key) const;
00652 template<class charT> const Fastcgipp::Http::Post<charT>& Fastcgipp::Http::Environment<charT>::findPost(const charT* key) const
00653 {
00654 static const Post<charT> emptyPost;
00655 typename Posts::const_iterator it=posts.find(key);
00656 if(it==posts.end())
00657 return emptyPost;
00658 else
00659 return it->second;
00660 }