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 <algorithm> 00034 #include <map> 00035 #include <vector> 00036 00037 #include <fastcgi++/exceptions.hpp> 00038 #include <fastcgi++/protocol.hpp> 00039 00041 namespace Fastcgipp 00042 { 00044 namespace Http 00045 { 00047 00058 template<class charT> struct Post 00059 { 00061 enum Type { file, form } type; 00063 std::basic_string<charT> value; 00065 std::basic_string<charT>& filename; 00067 std::basic_string<charT> contentType; 00068 00070 const char* data() const { return m_data; } 00072 size_t size() const { return m_size; } 00074 char* steal() const { char* ptr=m_data; m_data=0; m_size=0; return ptr; } 00075 00076 Post(): filename(value), m_data(0), m_size(0) {} 00077 Post(const Post& x): 00078 type(x.type), 00079 value(x.value), 00080 filename(value), 00081 contentType(x.contentType), 00082 m_data(x.steal()), 00083 m_size(x.m_size) 00084 {} 00085 ~Post() { delete [] m_data; } 00086 private: 00088 mutable char* m_data; 00090 mutable size_t m_size; 00091 template<class T> friend class Environment; 00092 }; 00093 00095 enum RequestMethod 00096 { 00097 HTTP_METHOD_ERROR, 00098 HTTP_METHOD_HEAD, 00099 HTTP_METHOD_GET, 00100 HTTP_METHOD_POST, 00101 HTTP_METHOD_PUT, 00102 HTTP_METHOD_DELETE, 00103 HTTP_METHOD_TRACE, 00104 HTTP_METHOD_OPTIONS, 00105 HTTP_METHOD_CONNECT 00106 }; 00107 extern const char* requestMethodLabels[]; 00108 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]; } 00109 00111 00119 class Address 00120 { 00121 public: 00123 static const size_t size=16; 00124 00126 00129 const unsigned char* data() const { return m_data; } 00130 00132 00135 unsigned char* data() { return m_data; } 00136 00138 00141 Address operator=(const unsigned char* data_) { std::memcpy(m_data, data_, size); return *this; } 00142 00143 Address operator=(const Address& address) { std::memcpy(m_data, address.m_data, size); return *this; } 00144 Address(const Address& address) { std::memcpy(m_data, address.m_data, size); } 00145 Address() {} 00146 00148 00151 explicit Address(const unsigned char* data_) { std::memcpy(m_data, data_, size); } 00152 00154 00161 void assign(const char* start, const char* end); 00162 inline bool operator==(const Address& x) const { return std::memcmp(m_data, x.m_data, size)==0; } 00163 inline bool operator>(const Address& x) const { return std::memcmp(m_data, x.m_data, size)>0; } 00164 inline bool operator<(const Address& x) const { return std::memcmp(m_data, x.m_data, size)<0; } 00165 inline bool operator<=(const Address& x) const { return !(std::memcmp(m_data, x.m_data, size)>0); } 00166 inline bool operator>=(const Address& x) const { return !(std::memcmp(m_data, x.m_data, size)<0); } 00168 operator bool() const; 00169 Address operator&(const Address& x) const; 00170 00171 Address& operator&=(const Address& x); 00172 00174 void zero() { std::memset(m_data, 0, size); } 00175 00176 private: 00178 unsigned char m_data[size]; 00179 }; 00180 00182 00186 template<class charT, class Traits> std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const Address& address); 00188 00193 template<class charT, class Traits> std::basic_istream<charT, Traits>& operator>>(std::basic_istream<charT, Traits>& is, Address& address); 00194 00196 00202 template<class charT> struct Environment 00203 { 00205 std::basic_string<charT> host; 00207 std::basic_string<charT> userAgent; 00209 std::basic_string<charT> acceptContentTypes; 00211 std::basic_string<charT> acceptLanguages; 00213 std::basic_string<charT> acceptCharsets; 00215 std::basic_string<charT> referer; 00217 std::basic_string<charT> contentType; 00219 std::basic_string<charT> root; 00221 std::basic_string<charT> scriptName; 00223 RequestMethod requestMethod; 00225 std::basic_string<charT> requestUri; 00227 typedef std::vector<std::basic_string<charT> > PathInfo; 00228 PathInfo pathInfo; 00230 int etag; 00232 int keepAlive; 00234 unsigned int contentLength; 00236 Address serverAddress; 00238 Address remoteAddress; 00240 uint16_t serverPort; 00242 uint16_t remotePort; 00244 boost::posix_time::ptime ifModifiedSince; 00245 00246 typedef std::map<std::basic_string<charT>, std::basic_string<charT> > Cookies; 00248 Cookies cookies; 00250 const std::basic_string<charT>& findCookie(const charT* key) const; 00251 00252 typedef std::map<std::basic_string<charT>, std::basic_string<charT> > Gets; 00254 Gets gets; 00255 00257 00262 const std::basic_string<charT>& findGet(const charT* key) const; 00263 00265 00269 bool checkForGet(const charT* key) const; 00270 00271 typedef std::map<std::basic_string<charT>, Post<charT> > Posts; 00273 Posts posts; 00274 00276 00281 const Post<charT>& findPost(const charT* key) const; 00282 00284 00288 bool checkForPost(const charT* key) const; 00289 00291 00299 void fill(const char* data, size_t size); 00300 00302 00310 bool fillPostBuffer(const char* data, size_t size); 00311 00313 void parsePostsMultipart(); 00314 00316 void parsePostsUrlEncoded(); 00317 00319 void clearPostBuffer() { postBuffer.reset(); pPostBuffer=0; } 00320 00321 Environment(): etag(0), keepAlive(0), contentLength(0), serverPort(0), remotePort(0) {} 00322 private: 00324 boost::scoped_array<char> boundary; 00326 size_t boundarySize; 00327 00329 boost::scoped_array<char> postBuffer; 00331 char* pPostBuffer; 00333 size_t minPostBufferSize(const size_t size) { return std::min(size, size_t(postBuffer.get()+contentLength-pPostBuffer)); } 00334 }; 00335 00337 00343 void charToString(const char* data, size_t size, std::wstring& string); 00344 00346 00352 inline void charToString(const char* data, size_t size, std::string& string) { string.assign(data, size); } 00353 00355 00365 int atoi(const char* start, const char* end); 00366 00368 00375 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='&'); 00376 00378 00388 size_t percentEscapedToRealBytes(const char* source, char* destination, size_t size); 00389 00393 extern const char base64Characters[]; 00394 00407 template<class In, class Out> void base64Encode(In start, In end, Out destination); 00408 00425 template<class In, class Out> Out base64Decode(In start, In end, Out destination); 00426 00430 class SessionId 00431 { 00435 public: static const int size=12; 00436 00437 private: 00441 char data[size]; 00442 00446 boost::posix_time::ptime timestamp; 00447 00451 static bool seeded; 00452 00453 template<class T> friend class Sessions; 00454 public: 00458 SessionId(); 00459 00460 SessionId(const SessionId& x): timestamp(x.timestamp) { std::memcpy(data, x.data, size); } 00461 const SessionId& operator=(const SessionId& x) { std::memcpy(data, x.data, size); timestamp=x.timestamp; return *this; } 00462 00470 template<class charT> const SessionId& operator=(charT* data_); 00471 00479 template<class charT> SessionId(charT* data_) { *this=data_; } 00480 00481 template<class charT, class Traits> friend std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const SessionId& x); 00482 00483 bool operator<(const SessionId& x) const { return std::memcmp(data, x.data, SessionId::size)<0; } 00484 bool operator==(const SessionId& x) const { return std::memcmp(data, x.data, SessionId::size)==0; } 00485 00489 void refresh() const { *const_cast<boost::posix_time::ptime*>(×tamp)=boost::posix_time::second_clock::universal_time(); } 00490 00491 const char* getInternalPointer() const { return data; } 00492 }; 00493 00497 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; } 00498 00509 template<class T> class Sessions: public std::map<SessionId, T> 00510 { 00511 private: 00515 const boost::posix_time::seconds keepAlive; 00516 00520 const boost::posix_time::seconds cleanupFrequency; 00521 00525 boost::posix_time::ptime cleanupTime; 00526 public: 00527 typedef typename std::map<SessionId, T>::iterator iterator; 00528 typedef typename std::map<SessionId, T>::const_iterator const_iterator; 00535 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) { } 00536 00542 void cleanup(); 00543 00551 iterator generate(const T& value_ = T()); 00552 00553 boost::posix_time::ptime getExpiry(const_iterator it) const { return it->first.timestamp+keepAlive; } 00554 }; 00555 } 00556 } 00557 00558 template<class T> void Fastcgipp::Http::Sessions<T>::cleanup() 00559 { 00560 if(boost::posix_time::second_clock::universal_time() < cleanupTime) 00561 return; 00562 boost::posix_time::ptime oldest(boost::posix_time::second_clock::universal_time()-keepAlive); 00563 iterator it=this->begin(); 00564 while(it!=this->end()) 00565 { 00566 if(it->first.timestamp < oldest) 00567 erase(it++); 00568 else 00569 ++it; 00570 } 00571 cleanupTime=boost::posix_time::second_clock::universal_time()+cleanupFrequency; 00572 } 00573 00574 template<class In, class Out> Out Fastcgipp::Http::base64Decode(In start, In end, Out destination) 00575 { 00576 Out dest=destination; 00577 00578 for(int buffer, bitPos=-8, padStart; start!=end || bitPos>-6; ++dest) 00579 { 00580 if(bitPos==-8) 00581 { 00582 bitPos=18; 00583 padStart=-9; 00584 buffer=0; 00585 while(bitPos!=-6) 00586 { 00587 if(start==end) return destination; 00588 int value=*start++; 00589 if(value >= 'A' && 'Z' >= value) value -= 'A'; 00590 else if(value >= 'a' && 'z' >= value) value -= 'a' - 26; 00591 else if(value >= '0' && '9' >= value) value -= '0' - 52; 00592 else if(value == '+') value = 62; 00593 else if(value == '/') value = 63; 00594 else if(value == '=') { padStart=bitPos; break; } 00595 else return destination; 00596 00597 buffer |= value << bitPos; 00598 bitPos-=6; 00599 } 00600 bitPos=16; 00601 } 00602 00603 *dest = (buffer >> bitPos) & 0xff; 00604 bitPos-=8; 00605 if(padStart>=bitPos) 00606 { 00607 if( (padStart-bitPos)/6 ) 00608 return dest; 00609 else 00610 return ++dest; 00611 } 00612 } 00613 00614 return dest; 00615 } 00616 00617 template<class In, class Out> void Fastcgipp::Http::base64Encode(In start, In end, Out destination) 00618 { 00619 for(int buffer, bitPos=-6, padded; start!=end || bitPos>-6; ++destination) 00620 { 00621 if(bitPos==-6) 00622 { 00623 bitPos=16; 00624 buffer=0; 00625 padded=-6; 00626 while(bitPos!=-8) 00627 { 00628 if(start!=end) 00629 buffer |= (uint32_t)*(unsigned char*)start++ << bitPos; 00630 else padded+=6; 00631 bitPos-=8; 00632 } 00633 bitPos=18; 00634 } 00635 00636 if(padded == bitPos) 00637 { 00638 *destination='='; 00639 padded-=6; 00640 } 00641 else *destination=base64Characters[ (buffer >> bitPos)&0x3f ]; 00642 bitPos -= 6; 00643 } 00644 } 00645 00646 template<class T> typename Fastcgipp::Http::Sessions<T>::iterator Fastcgipp::Http::Sessions<T>::generate(const T& value_) 00647 { 00648 std::pair<iterator,bool> retVal; 00649 retVal.second=false; 00650 while(!retVal.second) 00651 retVal=insert(std::pair<SessionId, T>(SessionId(), value_)); 00652 return retVal.first; 00653 } 00654 00655 #endif