fastcgi++
http.hpp
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 #ifndef HTTP_HPP
00023 #define HTTP_HPP
00024 
00025 #include <string>
00026 #include <boost/shared_array.hpp>
00027 #include <boost/scoped_array.hpp>
00028 #include <boost/date_time/posix_time/posix_time.hpp>
00029 #include <ostream>
00030 #include <istream>
00031 #include <cstring>
00032 #include <sstream>
00033 #include <map>
00034 #include <vector>
00035 
00036 #include <fastcgi++/exceptions.hpp>
00037 #include <fastcgi++/protocol.hpp>
00038 
00040 namespace Fastcgipp
00041 {
00043    namespace Http
00044    {
00046 
00057       template<class charT> struct Post
00058       {
00060          enum Type { file, form } type;
00062          std::basic_string<charT> value;
00064          std::basic_string<charT>& filename;
00066          std::basic_string<charT> contentType;
00067 
00069          const char* data() const { return m_data; }
00071          size_t size() const { return m_size; }
00073          char* steal() const { char* ptr=m_data; m_data=0; m_size=0; return ptr; }
00074 
00075          Post(): filename(value), m_data(0), m_size(0) {}
00076          Post(const Post& x):
00077             type(x.type),
00078             value(x.value),
00079             filename(value),
00080             contentType(x.contentType),
00081             m_size(x.m_size),
00082             m_data(x.steal())
00083          {}
00084          ~Post() { delete [] m_data; }
00085       private:
00087          mutable char* m_data;
00089          mutable size_t m_size;
00090          template<class T> friend class Environment;
00091       };
00092 
00094       enum RequestMethod
00095       {
00096          HTTP_METHOD_ERROR,
00097          HTTP_METHOD_HEAD,
00098          HTTP_METHOD_GET,
00099          HTTP_METHOD_POST,
00100          HTTP_METHOD_PUT,
00101          HTTP_METHOD_DELETE,
00102          HTTP_METHOD_TRACE,
00103          HTTP_METHOD_OPTIONS,
00104          HTTP_METHOD_CONNECT
00105       };
00106       extern const char* requestMethodLabels[];
00107       template<class charT, class Traits> inline std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const RequestMethod requestMethod) { return os << requestMethodLabels[requestMethod]; }
00108    
00110 
00116       class Address
00117       {
00118       public:
00120 
00123          const unsigned int& getInt() const { return data; }
00125 
00128          Address operator=(unsigned int data_) { data=data_; return *this; }
00129          Address operator=(Address address) { data=address.data; return *this; }
00130          Address(const Address& address): data(address.data) { }
00132 
00135          explicit Address(unsigned int data_): data(data_) { }
00137          Address(): data(0) { }
00139 
00146          void assign(const char* start, const char* end);
00147          inline bool operator==(const Address x) const { return data==x.data; }
00148          inline bool operator>(const Address x) const { return data>x.data; }
00149          inline bool operator<(const Address x) const { return data<x.data; }
00150          inline bool operator<=(const Address x) const { return data<=x.data; }
00151          inline bool operator>=(const Address x) const { return data>=x.data; }
00152          inline Address operator&(const Address x) const { return Address(data&x.data); }
00153 
00154       private:
00155          template<class charT, class Traits> friend std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const Address& address);
00156          template<class charT, class Traits> friend std::basic_istream<charT, Traits>& operator>>(std::basic_istream<charT, Traits>& is, Address& address);
00158          unsigned int data;
00159       };
00160 
00162 
00165       template<class charT, class Traits> std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const Address& address);
00167 
00171       template<class charT, class Traits> std::basic_istream<charT, Traits>& operator>>(std::basic_istream<charT, Traits>& is, Address& address);
00172 
00174 
00180       template<class charT> struct Environment
00181       {
00183          std::basic_string<charT> host;
00185          std::basic_string<charT> userAgent;
00187          std::basic_string<charT> acceptContentTypes;
00189          std::basic_string<charT> acceptLanguages;
00191          std::basic_string<charT> acceptCharsets;
00193          std::basic_string<charT> referer;
00195          std::basic_string<charT> contentType;
00197          std::basic_string<charT> root;
00199          std::basic_string<charT> scriptName;
00201          RequestMethod requestMethod;
00203          std::basic_string<charT> requestUri;
00205          typedef std::vector<std::basic_string<charT> > PathInfo;
00206          PathInfo pathInfo;
00208          int etag;
00210          int keepAlive;
00212          unsigned int contentLength;
00214          Address serverAddress;
00216          Address remoteAddress;
00218          uint16_t serverPort;
00220          uint16_t remotePort;
00222          boost::posix_time::ptime ifModifiedSince;
00223 
00224          typedef std::map<std::basic_string<charT>, std::basic_string<charT> > Cookies;
00226          Cookies cookies;
00228          const std::basic_string<charT>& findCookie(const charT* key) const;
00229 
00230          typedef std::map<std::basic_string<charT>, std::basic_string<charT> > Gets;
00232          Gets gets;
00233 
00235 
00240          const std::basic_string<charT>& findGet(const charT* key) const;
00241 
00243 
00247          bool checkForGet(const charT* key) const;
00248 
00249          typedef std::map<std::basic_string<charT>, Post<charT> > Posts;
00251          Posts posts;
00252 
00254 
00259          const Post<charT>& findPost(const charT* key) const;
00260 
00262 
00266          bool checkForPost(const charT* key) const;
00267 
00269 
00277          void fill(const char* data, size_t size);
00279 
00288          void fillPostsMultipart(const char* data, size_t size);
00289 
00291 
00301          void fillPostsUrlEncoded(const char* data, size_t size);
00302 
00304          void clearPostBuffer() { postBuffer.reset(); postBufferSize=0; }
00305 
00306          Environment(): etag(0), keepAlive(0), serverPort(0), remotePort(0), contentLength(0) {}
00307       private:
00309          boost::scoped_array<char> boundary;
00311          size_t boundarySize;
00312 
00314          boost::scoped_array<char> postBuffer;
00316          size_t postBufferSize;
00317       };
00318 
00320 
00326       void charToString(const char* data, size_t size, std::wstring& string);
00327 
00329 
00335       inline void charToString(const char* data, size_t size, std::string& string) { string.assign(data, size); }
00336 
00338 
00348       int atoi(const char* start, const char* end);
00349 
00351 
00358       template<class charT> void decodeUrlEncoded(const char* data, size_t size, std::map<std::basic_string<charT>, std::basic_string<charT> >& output, const char fieldSeperator='&');
00359 
00361 
00371       size_t percentEscapedToRealBytes(const char* source, char* destination, size_t size);
00372 
00376       extern const char base64Characters[];
00377 
00390       template<class In, class Out> void base64Encode(In start, In end, Out destination);
00391 
00408       template<class In, class Out> Out base64Decode(In start, In end, Out destination);
00409 
00413       class SessionId
00414       {
00418          public: static const int size=12;
00419 
00420       private:
00424          char data[size];
00425 
00429          boost::posix_time::ptime timestamp;
00430 
00434          static bool seeded;
00435 
00436          template<class T> friend class Sessions;
00437       public:
00441          SessionId();
00442 
00443          SessionId(const SessionId& x): timestamp(x.timestamp) { std::memcpy(data, x.data, size); }
00444          const SessionId& operator=(const SessionId& x) { std::memcpy(data, x.data, size); timestamp=x.timestamp; return *this; }
00445 
00453          template<class charT> const SessionId& operator=(charT* data_);
00454 
00462          template<class charT> SessionId(charT* data_) { *this=data_; }
00463 
00464          template<class charT, class Traits> friend std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const SessionId& x);
00465 
00466          bool operator<(const SessionId& x) const { return std::memcmp(data, x.data, SessionId::size)<0; }
00467          bool operator==(const SessionId& x) const { return std::memcmp(data, x.data, SessionId::size)==0; }
00468 
00472          void refresh() const { *const_cast<boost::posix_time::ptime*>(&timestamp)=boost::posix_time::second_clock::universal_time(); }
00473 
00474          const char* getInternalPointer() const { return data; }
00475       };
00476 
00480       template<class charT, class Traits> std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const SessionId& x) { base64Encode(x.data, x.data+SessionId::size, std::ostream_iterator<charT, charT, Traits>(os)); return os; }
00481 
00492       template<class T> class Sessions: public std::map<SessionId, T>
00493       {
00494       private:
00498          const boost::posix_time::seconds keepAlive;
00499 
00503          const boost::posix_time::seconds cleanupFrequency;
00504 
00508          boost::posix_time::ptime cleanupTime;
00509       public:
00510          typedef typename std::map<SessionId, T>::iterator iterator;
00511          typedef typename std::map<SessionId, T>::const_iterator const_iterator;
00518          Sessions(int keepAlive_, int cleanupFrequency_): keepAlive(boost::posix_time::seconds(keepAlive_)), cleanupFrequency(boost::posix_time::seconds(cleanupFrequency_)), cleanupTime(boost::posix_time::second_clock::universal_time()+cleanupFrequency) { }
00519             
00525          void cleanup();
00526 
00534          iterator generate(const T& value_ = T());
00535 
00536          boost::posix_time::ptime getExpiry(const_iterator it) const { return it->first.timestamp+keepAlive; }
00537       };
00538    }
00539 }
00540 
00541 template<class T> void Fastcgipp::Http::Sessions<T>::cleanup()
00542 {
00543    if(boost::posix_time::second_clock::universal_time() < cleanupTime)
00544       return;
00545    boost::posix_time::ptime oldest(boost::posix_time::second_clock::universal_time()-keepAlive);
00546    iterator it=this->begin();
00547    while(it!=this->end())
00548    {
00549       if(it->first.timestamp < oldest)
00550          erase(it++);
00551       else
00552          ++it;
00553    }
00554    cleanupTime=boost::posix_time::second_clock::universal_time()+cleanupFrequency;
00555 }
00556 
00557 template<class In, class Out> Out Fastcgipp::Http::base64Decode(In start, In end, Out destination)
00558 {
00559    Out dest=destination;
00560 
00561    for(int buffer, bitPos=-8, padStart; start!=end || bitPos>-6; ++dest)
00562    {
00563       if(bitPos==-8)
00564       {
00565          bitPos=18;
00566          padStart=-9;
00567          buffer=0;
00568          while(bitPos!=-6)
00569          {
00570             if(start==end) return destination;
00571             int value=*start++;
00572             if(value >= 'A' && 'Z' >= value) value -= 'A';
00573             else if(value >= 'a' && 'z' >= value) value -= 'a' - 26;
00574             else if(value >= '0' && '9' >= value) value -= '0' - 52;
00575             else if(value == '+') value = 62;
00576             else if(value == '/') value = 63;
00577             else if(value == '=') { padStart=bitPos; break; }
00578             else return destination;
00579 
00580             buffer |= value << bitPos;
00581             bitPos-=6;
00582          }
00583          bitPos=16;
00584       }
00585 
00586       *dest = (buffer >> bitPos) & 0xff;
00587       bitPos-=8;
00588       if(padStart>=bitPos)
00589       {
00590          if( (padStart-bitPos)/6 )
00591             return dest;
00592          else
00593             return ++dest;
00594       }
00595    }
00596 
00597    return dest;
00598 }
00599 
00600 template<class In, class Out> void Fastcgipp::Http::base64Encode(In start, In end, Out destination)
00601 {
00602    for(int buffer, bitPos=-6, padded; start!=end || bitPos>-6; ++destination)
00603    {
00604       if(bitPos==-6)
00605       {
00606          bitPos=16;
00607          buffer=0;
00608          padded=-6;
00609          while(bitPos!=-8)
00610          {
00611             if(start!=end) 
00612                buffer |= (uint32_t)*(unsigned char*)start++ << bitPos;
00613             else padded+=6;
00614             bitPos-=8;
00615          }
00616          bitPos=18;
00617       }
00618 
00619       if(padded == bitPos)
00620       {
00621          *destination='=';
00622          padded-=6;
00623       }
00624       else *destination=base64Characters[ (buffer >> bitPos)&0x3f ];
00625       bitPos -= 6;
00626    }
00627 }
00628 
00629 template<class T> typename Fastcgipp::Http::Sessions<T>::iterator Fastcgipp::Http::Sessions<T>::generate(const T& value_)
00630 {
00631    std::pair<iterator,bool> retVal;
00632    retVal.second=false;
00633    while(!retVal.second)
00634       retVal=insert(std::pair<SessionId, T>(SessionId(), value_));
00635    return retVal.first;
00636 }
00637 
00638 #endif