fastcgi++
http.cpp
Go to the documentation of this file.
00001 
00002 /***************************************************************************
00003 * Copyright (C) 2007 Eddie Carle [eddie@erctech.org]                       *
00004 *                                                                          *
00005 * This file is part of fastcgi++.                                          *
00006 *                                                                          *
00007 * fastcgi++ is free software: you can redistribute it and/or modify it     *
00008 * under the terms of the GNU Lesser General Public License as  published   *
00009 * by the Free Software Foundation, either version 3 of the License, or (at *
00010 * your option) any later version.                                          *
00011 *                                                                          *
00012 * fastcgi++ is distributed in the hope that it will be useful, but WITHOUT *
00013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    *
00014 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public     *
00015 * License for more details.                                                *
00016 *                                                                          *
00017 * You should have received a copy of the GNU Lesser General Public License *
00018 * along with fastcgi++.  If not, see <http://www.gnu.org/licenses/>.       *
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          {
00246             boost::scoped_array<char> buffer(new char[valueSize]);
00247             const char* source=value;
00248             int size=-1;
00249             for(; source<value+valueSize+1; ++source, ++size)
00250             {
00251                if(*source == '/' || source == value+valueSize)
00252                {
00253                   if(size > 0)
00254                   {
00255                      percentEscapedToRealBytes(source-size, buffer.get(), size);
00256                      pathInfo.push_back(std::basic_string<charT>());
00257                      charToString(buffer.get(), size, pathInfo.back());
00258                   }
00259                   size=-1;                
00260                }
00261             }
00262          }
00263          break;
00264       case 11:
00265          if(!memcmp(name, "HTTP_ACCEPT", 11))
00266             charToString(value, valueSize, acceptContentTypes);
00267          else if(!memcmp(name, "HTTP_COOKIE", 11))
00268             decodeUrlEncoded(value, valueSize, cookies, ';');
00269          else if(!memcmp(name, "SERVER_ADDR", 11))
00270             serverAddress.assign(value, value+valueSize);
00271          else if(!memcmp(name, "REMOTE_ADDR", 11))
00272             remoteAddress.assign(value, value+valueSize);
00273          else if(!memcmp(name, "SERVER_PORT", 11))
00274             serverPort=atoi(value, value+valueSize);
00275          else if(!memcmp(name, "REMOTE_PORT", 11))
00276             remotePort=atoi(value, value+valueSize);
00277          else if(!memcmp(name, "SCRIPT_NAME", 11))
00278             charToString(value, valueSize, scriptName);
00279          else if(!memcmp(name, "REQUEST_URI", 11))
00280             charToString(value, valueSize, requestUri);
00281          break;
00282       case 12:
00283          if(!memcmp(name, "HTTP_REFERER", 12) && valueSize)
00284             charToString(value, valueSize, referer);
00285          else if(!memcmp(name, "CONTENT_TYPE", 12))
00286          {
00287             const char* end=(char*)memchr(value, ';', valueSize);
00288             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(!memcmp(name, "QUERY_STRING", 12) && valueSize)
00301             decodeUrlEncoded(value, valueSize, gets);
00302          break;
00303       case 13:
00304          if(!memcmp(name, "DOCUMENT_ROOT", 13))
00305             charToString(value, valueSize, root);
00306          break;
00307       case 14:
00308          if(!memcmp(name, "REQUEST_METHOD", 14))
00309          {
00310             requestMethod = HTTP_METHOD_ERROR;
00311             switch(valueSize)
00312             {
00313             case 3:
00314                if(!memcmp(value, requestMethodLabels[HTTP_METHOD_GET], 3)) requestMethod = HTTP_METHOD_GET;
00315                else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_PUT], 3)) requestMethod = HTTP_METHOD_PUT;
00316                break;
00317             case 4:
00318                if(!memcmp(value, requestMethodLabels[HTTP_METHOD_HEAD], 4)) requestMethod = HTTP_METHOD_HEAD;
00319                else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_POST], 4)) requestMethod = HTTP_METHOD_POST;
00320                break;
00321             case 5:
00322                if(!memcmp(value, requestMethodLabels[HTTP_METHOD_TRACE], 5)) requestMethod = HTTP_METHOD_TRACE;
00323                break;
00324             case 6:
00325                if(!memcmp(value, requestMethodLabels[HTTP_METHOD_DELETE], 6)) requestMethod = HTTP_METHOD_DELETE;
00326                break;
00327             case 7:
00328                if(!memcmp(value, requestMethodLabels[HTTP_METHOD_OPTIONS], 7)) requestMethod = HTTP_METHOD_OPTIONS;
00329                else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_OPTIONS], 7)) requestMethod = HTTP_METHOD_CONNECT;
00330                break;
00331             }
00332          }
00333          else if(!memcmp(name, "CONTENT_LENGTH", 14))
00334             contentLength=atoi(value, value+valueSize);
00335          break;
00336       case 15:
00337          if(!memcmp(name, "HTTP_USER_AGENT", 15))
00338             charToString(value, valueSize, userAgent);
00339          else if(!memcmp(name, "HTTP_KEEP_ALIVE", 15))
00340             keepAlive=atoi(value, value+valueSize);
00341          break;
00342       case 18:
00343          if(!memcmp(name, "HTTP_IF_NONE_MATCH", 18))
00344             etag=atoi(value, value+valueSize);
00345          break;
00346       case 19:
00347          if(!memcmp(name, "HTTP_ACCEPT_CHARSET", 19))
00348             charToString(value, valueSize, acceptCharsets);
00349          break;
00350       case 20:
00351          if(!memcmp(name, "HTTP_ACCEPT_LANGUAGE", 20))
00352             charToString(value, valueSize, acceptLanguages);
00353          break;
00354       case 22:
00355          if(!memcmp(name, "HTTP_IF_MODIFIED_SINCE", 22))
00356          {
00357             stringstream dateStream;
00358             dateStream.write(value, valueSize);
00359             dateStream.imbue(locale(locale::classic(), new posix_time::time_input_facet("%a, %d %b %Y %H:%M:%S GMT")));
00360             dateStream >> ifModifiedSince;
00361          }
00362          break;
00363       }
00364    }}
00365 }
00366 
00367 template void Fastcgipp::Http::Environment<char>::fillPostsMultipart(const char* data, size_t size);
00368 template void Fastcgipp::Http::Environment<wchar_t>::fillPostsMultipart(const char* data, size_t size);
00369 template<class charT> void Fastcgipp::Http::Environment<charT>::fillPostsMultipart(const char* data, size_t size)
00370 {
00371    using namespace std;
00372    while(1)
00373    {{
00374       size_t bufferSize=postBufferSize+size;
00375       char* buffer=new char[bufferSize];
00376       if(postBufferSize) memcpy(buffer, postBuffer.get(), postBufferSize);
00377       memcpy(buffer+postBufferSize, data, size);
00378       postBuffer.reset(buffer);
00379       postBufferSize=bufferSize;
00380 
00381       const char* end=0;
00382       for(const char* i=buffer+boundarySize; i<buffer+bufferSize-boundarySize; ++i)
00383          if(!memcmp(i, boundary.get(), boundarySize))
00384          {
00385             end=i;
00386             break;
00387          }
00388       
00389       if(!end)
00390          return;
00391 
00392       end-=4;
00393       const char* start=buffer+boundarySize+2;
00394       const char* bodyStart=start;
00395       for(; bodyStart<=end-4; ++bodyStart)
00396          if(!memcmp(bodyStart, "\r\n\r\n", 4)) break;
00397       bodyStart+=4;
00398 
00399 
00400       const char* contentTypeStart;
00401       ssize_t contentTypeSize=-1;
00402       const char* nameStart;
00403       ssize_t nameSize=-1;
00404       const char* filenameStart;
00405       ssize_t filenameSize=-1;
00406       // Fill out above values
00407       {
00408          const char cContentType[] = "Content-Type: ";
00409          const char cContentDisposition[] = "Content-Disposition: ";
00410          const char cFilename[] = "filename=\"";
00411          const char cName[] = "name=\"";
00412 
00413          enum ParseState { TITLE, CONTENT_DISPOSITION, FILENAME, NAME, CONTENT_TYPE, SKIP } parseState=TITLE;
00414          for(const char* i=start; i<bodyStart; ++i)
00415          {
00416             switch(*i)
00417             {
00418                case '\n':
00419                case '\r':
00420                {
00421                   if(parseState==CONTENT_TYPE)
00422                      contentTypeSize=i-contentTypeStart;
00423                   parseState=TITLE;
00424                   break;
00425                }
00426 
00427                case '"':
00428                {
00429                   if(parseState==FILENAME)
00430                   {
00431                      filenameSize=i-filenameStart;
00432                      parseState=CONTENT_DISPOSITION;
00433                   }
00434                   else if(parseState==NAME)
00435                   {
00436                      nameSize=i-nameStart;
00437                      parseState=CONTENT_DISPOSITION;
00438                   }
00439                   break;
00440                }
00441 
00442                default:
00443                {
00444                   if(parseState==TITLE)
00445                   {
00446                      if(sizeof(cContentType)-1 <= bodyStart-i && !memcmp(cContentType, i, sizeof(cContentType)-1))
00447                      {
00448                         parseState=CONTENT_TYPE;
00449                         i += sizeof(cContentType)-1;
00450                         contentTypeStart=i;
00451                      }
00452                      else if(sizeof(cContentDisposition)-1 <= bodyStart-i && !memcmp(cContentDisposition, i, sizeof(cContentDisposition)-1))
00453                      {
00454                         parseState=CONTENT_DISPOSITION;
00455                         i += sizeof(cContentDisposition)-1;
00456                      }
00457                      else
00458                         parseState=SKIP;
00459                   }
00460                   else if(parseState==CONTENT_DISPOSITION)
00461                   {
00462                      if(sizeof(cFilename)-1 <= bodyStart-i && !memcmp(cFilename, i, sizeof(cFilename)-1))
00463                      {
00464                         parseState=FILENAME;
00465                         i += sizeof(cFilename)-1;
00466                         filenameStart=i;
00467                      }
00468                      else if(sizeof(cName)-1 <= bodyStart-i && !memcmp(cName, i, sizeof(cName)-1))
00469                      {
00470                         parseState=NAME;
00471                         i += sizeof(cName)-1;
00472                         nameStart=i;
00473                      }
00474                   }
00475                   break;
00476                }
00477             }
00478          }
00479       }
00480 
00481       
00482       if(nameSize != -1)
00483       {
00484          basic_string<charT> name;
00485          charToString(nameStart, nameSize, name);
00486 
00487          Post<charT>& thePost=posts[name];
00488          if(contentTypeSize != -1)
00489          {
00490             thePost.type=Post<charT>::file;
00491             charToString(contentTypeStart, contentTypeSize, thePost.contentType);
00492             if(filenameSize != -1) charToString(filenameStart, filenameSize, thePost.filename);
00493             thePost.m_size=end-bodyStart;
00494             if(thePost.size())
00495             {
00496                thePost.m_data = new char[thePost.size()];
00497                memcpy(thePost.m_data, bodyStart, thePost.size());
00498             }
00499          }
00500          else
00501          {
00502             thePost.type=Post<charT>::form;
00503             charToString(bodyStart, end-bodyStart, thePost.value);
00504          }
00505       }
00506 
00507       bufferSize=bufferSize-(end-buffer+2);
00508       if(!bufferSize)
00509       {
00510          postBuffer.reset();
00511          return;
00512       }
00513       buffer=new char[bufferSize];
00514       memcpy(buffer, end+2, bufferSize);
00515       postBuffer.reset(buffer);
00516       postBufferSize=bufferSize;
00517       size=0;
00518    }}
00519 }
00520 
00521 template void Fastcgipp::Http::Environment<char>::fillPostsUrlEncoded(const char* data, size_t size);
00522 template void Fastcgipp::Http::Environment<wchar_t>::fillPostsUrlEncoded(const char* data, size_t size);
00523 template<class charT> void Fastcgipp::Http::Environment<charT>::fillPostsUrlEncoded(const char* data, size_t size)
00524 {
00525    using namespace std;
00526 
00527    if(!postBuffer.get() && size)
00528    {
00529       postBuffer.reset(new char[contentLength]);
00530       postBufferSize=0;
00531    }
00532 
00533    // We don't want a buffer overflow so only process a max length of processLength
00534    size=min(size, contentLength-postBufferSize);
00535 
00536    memcpy(postBuffer.get()+postBufferSize, data, size);
00537    postBufferSize+=size;
00538 
00539    if(postBufferSize != contentLength)
00540       return;
00541 
00542    char* nameStart=postBuffer.get();
00543    size_t nameSize;
00544    char* valueStart=0;
00545    size_t valueSize;
00546    for(char* i=postBuffer.get(); i<=postBuffer.get()+postBufferSize; ++i)
00547    {
00548       if(*i == '=' && nameStart && !valueStart)
00549       {
00550          nameSize=percentEscapedToRealBytes(nameStart, nameStart, i-nameStart);
00551          valueStart=i+1;
00552       }
00553       else if( (i==postBuffer.get()+postBufferSize || *i == '&') && nameStart && valueStart)
00554       {
00555          valueSize=percentEscapedToRealBytes(valueStart, valueStart, i-valueStart);
00556 
00557          basic_string<charT> name;
00558          charToString(nameStart, nameSize, name);
00559          nameStart=i+1;
00560          Post<charT>& thePost=posts[name];
00561          thePost.type=Post<charT>::form;
00562          charToString(valueStart, valueSize, thePost.value);
00563          valueStart=0;
00564       }
00565    }
00566 }
00567 
00568 bool Fastcgipp::Http::SessionId::seeded=false;
00569 
00570 Fastcgipp::Http::SessionId::SessionId()
00571 {
00572    if(!seeded)
00573    {
00574       std::srand(boost::posix_time::microsec_clock::universal_time().time_of_day().fractional_seconds());
00575       seeded=true;
00576    }
00577 
00578    for(char* i=data; i<data+size; ++i)
00579       *i=char(rand()%256);
00580    timestamp = boost::posix_time::second_clock::universal_time();
00581 }
00582 
00583 template const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=<const char>(const char* data_);
00584 template const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=<const wchar_t>(const wchar_t* data_);
00585 template<class charT> const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=(charT* data_)
00586 {
00587    std::memset(data, 0, size);
00588    base64Decode(data_, data_+size*4/3, data);
00589    timestamp = boost::posix_time::second_clock::universal_time();
00590    return *this;
00591 }
00592 
00593 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);
00594 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);
00595 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)
00596 {
00597    using namespace std;
00598 
00599    boost::scoped_array<char> buffer(new char[size]);
00600    memcpy(buffer.get(), data, size);
00601 
00602    char* nameStart=buffer.get();
00603    size_t nameSize;
00604    char* valueStart=0;
00605    size_t valueSize;
00606    for(char* i=buffer.get(); i<=buffer.get()+size; ++i)
00607    {
00608       if(*i == ' ' && nameStart && !valueStart)
00609          ++nameStart;
00610 
00611       else if(*i == '=' && nameStart && !valueStart)
00612       {
00613          nameSize=percentEscapedToRealBytes(nameStart, nameStart, i-nameStart);
00614          valueStart=i+1;
00615       }
00616       else if( (i==buffer.get()+size || *i == fieldSeperator) && nameStart && valueStart)
00617       {
00618          valueSize=percentEscapedToRealBytes(valueStart, valueStart, i-valueStart);
00619 
00620          basic_string<charT> name;
00621          charToString(nameStart, nameSize, name);
00622          nameStart=i+1;
00623          basic_string<charT>& value=output[name];
00624          charToString(valueStart, valueSize, value);
00625          valueStart=0;
00626       }
00627    }
00628 }
00629 
00630 const char Fastcgipp::Http::base64Characters[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00631 const char* Fastcgipp::Http::requestMethodLabels[]= {
00632    "ERROR",
00633    "HEAD",
00634    "GET",
00635    "POST",
00636    "PUT",
00637    "DELETE",
00638    "TRACE",
00639    "OPTIONS",
00640    "CONNECT"
00641 };
00642 
00643 template const std::basic_string<char>& Fastcgipp::Http::Environment<char>::findCookie(const char* key) const;
00644 template const std::basic_string<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findCookie(const wchar_t* key) const;
00645 template<class charT> const std::basic_string<charT>& Fastcgipp::Http::Environment<charT>::findCookie(const charT* key) const
00646 {
00647    static const std::basic_string<charT> emptyString;
00648    typename Cookies::const_iterator it=cookies.find(key);
00649    if(it==cookies.end())
00650       return emptyString;
00651    else
00652       return it->second;
00653 }
00654 
00655 template const std::basic_string<char>& Fastcgipp::Http::Environment<char>::findGet(const char* key) const;
00656 template const std::basic_string<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findGet(const wchar_t* key) const;
00657 template<class charT> const std::basic_string<charT>& Fastcgipp::Http::Environment<charT>::findGet(const charT* key) const
00658 {
00659    static const std::basic_string<charT> emptyString;
00660    typename Gets::const_iterator it=gets.find(key);
00661    if(it==gets.end())
00662       return emptyString;
00663    else
00664       return it->second;
00665 }
00666 
00667 template const Fastcgipp::Http::Post<char>& Fastcgipp::Http::Environment<char>::findPost(const char* key) const;
00668 template const Fastcgipp::Http::Post<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findPost(const wchar_t* key) const;
00669 template<class charT> const Fastcgipp::Http::Post<charT>& Fastcgipp::Http::Environment<charT>::findPost(const charT* key) const
00670 {
00671    static const Post<charT> emptyPost;
00672    typename Posts::const_iterator it=posts.find(key);
00673    if(it==posts.end())
00674       return emptyPost;
00675    else
00676       return it->second;
00677 }
00678 
00679 template bool Fastcgipp::Http::Environment<char>::checkForGet(const char* key) const;
00680 template bool Fastcgipp::Http::Environment<wchar_t>::checkForGet(const wchar_t* key) const;
00681 template<class charT> bool Fastcgipp::Http::Environment<charT>::checkForGet(const charT* key) const
00682 {
00683    typename Gets::const_iterator it=gets.find(key);
00684    if(it==gets.end())
00685       return false;
00686    else
00687       return true;
00688 }
00689 
00690 template bool Fastcgipp::Http::Environment<char>::checkForPost(const char* key) const;
00691 template bool Fastcgipp::Http::Environment<wchar_t>::checkForPost(const wchar_t* key) const;
00692 template<class charT> bool Fastcgipp::Http::Environment<charT>::checkForPost(const charT* key) const
00693 {
00694    typename Posts::const_iterator it=posts.find(key);
00695    if(it==posts.end())
00696       return false;
00697    else
00698       return true;
00699 }