00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00035 #include <fastcgi++/exceptions.hpp>
00036 #include <fastcgi++/protocol.hpp>
00037
00039 namespace Fastcgipp
00040 {
00042 namespace Http
00043 {
00045
00056 template<class charT> struct Post
00057 {
00059 enum Type { file, form } type;
00061 std::basic_string<charT> value;
00063 std::basic_string<charT>& filename;
00065 std::basic_string<charT> contentType;
00067 boost::shared_array<char> data;
00069 size_t size;
00070
00071 Post(): filename(value) {}
00072 Post(const Post& x):
00073 type(x.type),
00074 value(x.value),
00075 filename(value),
00076 contentType(x.contentType),
00077 data(x.data),
00078 size(x.size)
00079 {}
00080 };
00081
00083 enum RequestMethod
00084 {
00085 HTTP_METHOD_ERROR,
00086 HTTP_METHOD_HEAD,
00087 HTTP_METHOD_GET,
00088 HTTP_METHOD_POST,
00089 HTTP_METHOD_PUT,
00090 HTTP_METHOD_DELETE,
00091 HTTP_METHOD_TRACE,
00092 HTTP_METHOD_OPTIONS,
00093 HTTP_METHOD_CONNECT
00094 };
00095 extern const char* requestMethodLabels[];
00096 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]; }
00097
00099
00105 class Address
00106 {
00107 public:
00109
00112 const unsigned int& getInt() const { return data; }
00114
00117 Address operator=(unsigned int data_) { data=data_; return *this; }
00118 Address operator=(Address address) { data=address.data; return *this; }
00119 Address(const Address& address): data(address.data) { }
00121
00124 explicit Address(unsigned int data_): data(data_) { }
00126 Address(): data(0) { }
00128
00135 void assign(const char* start, const char* end);
00136 inline bool operator==(const Address x) const { return data==x.data; }
00137 inline bool operator>(const Address x) const { return data>x.data; }
00138 inline bool operator<(const Address x) const { return data<x.data; }
00139 inline bool operator<=(const Address x) const { return data<=x.data; }
00140 inline bool operator>=(const Address x) const { return data>=x.data; }
00141 inline Address operator&(const Address x) const { return Address(data&x.data); }
00142
00143 private:
00144 template<class charT, class Traits> friend std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const Address& address);
00145 template<class charT, class Traits> friend std::basic_istream<charT, Traits>& operator>>(std::basic_istream<charT, Traits>& is, Address& address);
00147 unsigned int data;
00148 };
00149
00151
00154 template<class charT, class Traits> std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const Address& address);
00156
00160 template<class charT, class Traits> std::basic_istream<charT, Traits>& operator>>(std::basic_istream<charT, Traits>& is, Address& address);
00161
00163
00169 template<class charT> struct Environment
00170 {
00172 std::basic_string<charT> host;
00174 std::basic_string<charT> userAgent;
00176 std::basic_string<charT> acceptContentTypes;
00178 std::basic_string<charT> acceptLanguages;
00180 std::basic_string<charT> acceptCharsets;
00182 std::basic_string<charT> referer;
00184 std::basic_string<charT> contentType;
00186 std::basic_string<charT> root;
00188 std::basic_string<charT> scriptName;
00190 RequestMethod requestMethod;
00192 std::basic_string<charT> requestUri;
00194 std::basic_string<charT> pathInfo;
00196 int etag;
00198 int keepAlive;
00200 unsigned int contentLength;
00202 Address serverAddress;
00204 Address remoteAddress;
00206 uint16_t serverPort;
00208 uint16_t remotePort;
00210 boost::posix_time::ptime ifModifiedSince;
00211
00212 typedef std::map<std::basic_string<charT>, std::basic_string<charT> > Cookies;
00214 Cookies cookies;
00216 const std::basic_string<charT>& findCookie(const charT* key) const;
00217
00218 typedef std::map<std::basic_string<charT>, std::basic_string<charT> > Gets;
00220 Gets gets;
00222 const std::basic_string<charT>& findGet(const charT* key) const;
00223
00224 typedef std::map<std::basic_string<charT>, Post<charT> > Posts;
00226 Posts posts;
00228 const Post<charT>& findPost(const charT* key) const;
00229
00231
00239 void fill(const char* data, size_t size);
00241
00250 void fillPostsMultipart(const char* data, size_t size);
00251
00253
00263 void fillPostsUrlEncoded(const char* data, size_t size);
00264
00266 void clearPostBuffer() { postBuffer.reset(); postBufferSize=0; }
00267
00268 Environment(): etag(0), keepAlive(0), serverPort(0), remotePort(0), contentLength(0) {}
00269 private:
00271 boost::scoped_array<char> boundary;
00273 size_t boundarySize;
00274
00276 boost::scoped_array<char> postBuffer;
00278 size_t postBufferSize;
00279 };
00280
00282
00288 void charToString(const char* data, size_t size, std::wstring& string);
00289
00291
00297 inline void charToString(const char* data, size_t size, std::string& string) { string.assign(data, size); }
00298
00300
00310 int atoi(const char* start, const char* end);
00311
00313
00320 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='&');
00321
00323
00333 size_t percentEscapedToRealBytes(const char* source, char* destination, size_t size);
00334
00338 extern const char base64Characters[];
00339
00352 template<class In, class Out> void base64Encode(In start, In end, Out destination);
00353
00370 template<class In, class Out> Out base64Decode(In start, In end, Out destination);
00371
00375 class SessionId
00376 {
00380 public: static const int size=12;
00381
00382 private:
00386 char data[size];
00387
00391 boost::posix_time::ptime timestamp;
00392
00396 static bool seeded;
00397
00398 template<class T> friend class Sessions;
00399 public:
00403 SessionId();
00404
00405 SessionId(const SessionId& x): timestamp(x.timestamp) { std::memcpy(data, x.data, size); }
00406 const SessionId& operator=(const SessionId& x) { std::memcpy(data, x.data, size); timestamp=x.timestamp; return *this; }
00407
00415 template<class charT> const SessionId& operator=(charT* data_);
00416
00424 template<class charT> SessionId(charT* data_) { *this=data_; }
00425
00426 template<class charT, class Traits> friend std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const SessionId& x);
00427
00428 bool operator<(const SessionId& x) const { return std::memcmp(data, x.data, SessionId::size)<0; }
00429 bool operator==(const SessionId& x) const { return std::memcmp(data, x.data, SessionId::size)==0; }
00430
00434 void refresh() const { *const_cast<boost::posix_time::ptime*>(×tamp)=boost::posix_time::second_clock::universal_time(); }
00435
00436 const char* getInternalPointer() const { return data; }
00437 };
00438
00442 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; }
00443
00454 template<class T> class Sessions: public std::map<SessionId, T>
00455 {
00456 private:
00460 const boost::posix_time::seconds keepAlive;
00461
00465 const boost::posix_time::seconds cleanupFrequency;
00466
00470 boost::posix_time::ptime cleanupTime;
00471 public:
00472 typedef typename std::map<SessionId, T>::iterator iterator;
00473 typedef typename std::map<SessionId, T>::const_iterator const_iterator;
00480 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) { }
00481
00487 void cleanup();
00488
00496 iterator generate(const T& value_ = T());
00497
00498 boost::posix_time::ptime getExpiry(const_iterator it) const { return it->first.timestamp+keepAlive; }
00499 };
00500 }
00501 }
00502
00503 template<class T> void Fastcgipp::Http::Sessions<T>::cleanup()
00504 {
00505 if(boost::posix_time::second_clock::universal_time() < cleanupTime)
00506 return;
00507 boost::posix_time::ptime oldest(boost::posix_time::second_clock::universal_time()-keepAlive);
00508 iterator it=this->begin();
00509 while(it!=this->end())
00510 {
00511 if(it->first.timestamp < oldest)
00512 erase(it++);
00513 else
00514 ++it;
00515 }
00516 cleanupTime=boost::posix_time::second_clock::universal_time()+cleanupFrequency;
00517 }
00518
00519 template<class In, class Out> Out Fastcgipp::Http::base64Decode(In start, In end, Out destination)
00520 {
00521 Out dest=destination;
00522
00523 for(int buffer, bitPos=-8, padStart; start!=end || bitPos>-6; ++dest)
00524 {
00525 if(bitPos==-8)
00526 {
00527 bitPos=18;
00528 padStart=-9;
00529 buffer=0;
00530 while(bitPos!=-6)
00531 {
00532 if(start==end) return destination;
00533 int value=*start++;
00534 if(value >= 'A' && 'Z' >= value) value -= 'A';
00535 else if(value >= 'a' && 'z' >= value) value -= 'a' - 26;
00536 else if(value >= '0' && '9' >= value) value -= '0' - 52;
00537 else if(value == '+') value = 62;
00538 else if(value == '/') value = 63;
00539 else if(value == '=') { padStart=bitPos; break; }
00540 else return destination;
00541
00542 buffer |= value << bitPos;
00543 bitPos-=6;
00544 }
00545 bitPos=16;
00546 }
00547
00548 *dest = (buffer >> bitPos) & 0xff;
00549 bitPos-=8;
00550 if(padStart>=bitPos)
00551 {
00552 if( (padStart-bitPos)/6 )
00553 return dest;
00554 else
00555 return ++dest;
00556 }
00557 }
00558
00559 return dest;
00560 }
00561
00562 template<class In, class Out> void Fastcgipp::Http::base64Encode(In start, In end, Out destination)
00563 {
00564 for(int buffer, bitPos=-6, padded; start!=end || bitPos>-6; ++destination)
00565 {
00566 if(bitPos==-6)
00567 {
00568 bitPos=16;
00569 buffer=0;
00570 padded=-6;
00571 while(bitPos!=-8)
00572 {
00573 if(start!=end)
00574 buffer |= (uint32_t)*(unsigned char*)start++ << bitPos;
00575 else padded+=6;
00576 bitPos-=8;
00577 }
00578 bitPos=18;
00579 }
00580
00581 if(padded == bitPos)
00582 {
00583 *destination='=';
00584 padded-=6;
00585 }
00586 else *destination=base64Characters[ (buffer >> bitPos)&0x3f ];
00587 bitPos -= 6;
00588 }
00589 }
00590
00591 template<class T> typename Fastcgipp::Http::Sessions<T>::iterator Fastcgipp::Http::Sessions<T>::generate(const T& value_)
00592 {
00593 std::pair<iterator,bool> retVal;
00594 retVal.second=false;
00595 while(!retVal.second)
00596 retVal=insert(std::pair<SessionId, T>(SessionId(), value_));
00597 return retVal.first;
00598 }
00599
00600 #endif