fastcgi++
|
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*>(×tamp)=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