fastcgi++
http.hpp
Go to the documentation of this file.
1 
2 /***************************************************************************
3 * Copyright (C) 2007 Eddie Carle [eddie@erctech.org] *
4 * *
5 * This file is part of fastcgi++. *
6 * *
7 * fastcgi++ is free software: you can redistribute it and/or modify it *
8 * under the terms of the GNU Lesser General Public License as published *
9 * by the Free Software Foundation, either version 3 of the License, or (at *
10 * your option) any later version. *
11 * *
12 * fastcgi++ is distributed in the hope that it will be useful, but WITHOUT *
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public *
15 * License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public License *
18 * along with fastcgi++. If not, see <http://www.gnu.org/licenses/>. *
19 ****************************************************************************/
20 
21 
22 #ifndef HTTP_HPP
23 #define HTTP_HPP
24 
25 #include <string>
26 #include <boost/shared_array.hpp>
27 #include <boost/scoped_array.hpp>
28 #include <boost/date_time/posix_time/posix_time.hpp>
29 #include <ostream>
30 #include <istream>
31 #include <cstring>
32 #include <sstream>
33 #include <algorithm>
34 #include <map>
35 #include <vector>
36 
37 #include <fastcgi++/exceptions.hpp>
38 #include <fastcgi++/protocol.hpp>
39 
41 namespace Fastcgipp
42 {
44  namespace Http
45  {
47 
58  template<class charT> struct Post
59  {
61  enum Type { file, form } type;
63  std::basic_string<charT> value;
65  std::basic_string<charT>& filename;
67  std::basic_string<charT> contentType;
68 
70  const char* data() const { return m_data; }
72  size_t size() const { return m_size; }
74  char* steal() const { char* ptr=m_data; m_data=0; m_size=0; return ptr; }
75 
76  Post(): filename(value), m_data(0), m_size(0) {}
77  Post(const Post& x):
78  type(x.type),
79  value(x.value),
80  filename(value),
82  m_data(x.steal()),
83  m_size(x.m_size)
84  {}
85  ~Post() { delete [] m_data; }
86  private:
88  mutable char* m_data;
90  mutable size_t m_size;
91  template<class T> friend class Environment;
92  };
93 
96  {
106  };
107  extern const char* requestMethodLabels[];
108  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]; }
109 
111 
119  class Address
120  {
121  public:
123  static const size_t size=16;
124 
126 
129  const unsigned char* data() const { return m_data; }
130 
132 
135  unsigned char* data() { return m_data; }
136 
138 
141  Address operator=(const unsigned char* data_) { std::memcpy(m_data, data_, size); return *this; }
142 
143  Address operator=(const Address& address) { std::memcpy(m_data, address.m_data, size); return *this; }
144  Address(const Address& address) { std::memcpy(m_data, address.m_data, size); }
145  Address() {}
146 
148 
151  explicit Address(const unsigned char* data_) { std::memcpy(m_data, data_, size); }
152 
154 
161  void assign(const char* start, const char* end);
162  inline bool operator==(const Address& x) const { return std::memcmp(m_data, x.m_data, size)==0; }
163  inline bool operator>(const Address& x) const { return std::memcmp(m_data, x.m_data, size)>0; }
164  inline bool operator<(const Address& x) const { return std::memcmp(m_data, x.m_data, size)<0; }
165  inline bool operator<=(const Address& x) const { return !(std::memcmp(m_data, x.m_data, size)>0); }
166  inline bool operator>=(const Address& x) const { return !(std::memcmp(m_data, x.m_data, size)<0); }
168  operator bool() const;
169  Address operator&(const Address& x) const;
170 
171  Address& operator&=(const Address& x);
172 
174  void zero() { std::memset(m_data, 0, size); }
175 
176  private:
178  unsigned char m_data[size];
179  };
180 
182 
186  template<class charT, class Traits> std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const Address& address);
188 
193  template<class charT, class Traits> std::basic_istream<charT, Traits>& operator>>(std::basic_istream<charT, Traits>& is, Address& address);
194 
196 
202  template<class charT> struct Environment
203  {
205  std::basic_string<charT> host;
207  std::basic_string<charT> userAgent;
209  std::basic_string<charT> acceptContentTypes;
211  std::basic_string<charT> acceptLanguages;
213  std::basic_string<charT> acceptCharsets;
215  std::basic_string<charT> referer;
217  std::basic_string<charT> contentType;
219  std::basic_string<charT> root;
221  std::basic_string<charT> scriptName;
225  std::basic_string<charT> requestUri;
227  typedef std::vector<std::basic_string<charT> > PathInfo;
230  int etag;
234  unsigned int contentLength;
240  uint16_t serverPort;
242  uint16_t remotePort;
244  boost::posix_time::ptime ifModifiedSince;
245 
246  typedef std::map<std::basic_string<charT>, std::basic_string<charT> > Cookies;
250  const std::basic_string<charT>& findCookie(const charT* key) const;
251 
252  typedef std::map<std::basic_string<charT>, std::basic_string<charT> > Gets;
255 
257 
262  const std::basic_string<charT>& findGet(const charT* key) const;
263 
265 
269  bool checkForGet(const charT* key) const;
270 
271  typedef std::map<std::basic_string<charT>, Post<charT> > Posts;
274 
276 
281  const Post<charT>& findPost(const charT* key) const;
282 
284 
288  bool checkForPost(const charT* key) const;
289 
291 
299  void fill(const char* data, size_t size);
300 
302 
310  bool fillPostBuffer(const char* data, size_t size);
311 
313  void parsePostsMultipart();
314 
316  void parsePostsUrlEncoded();
317 
319  void clearPostBuffer() { postBuffer.reset(); pPostBuffer=0; }
320 
322  private:
324  boost::scoped_array<char> boundary;
326  size_t boundarySize;
327 
329  boost::scoped_array<char> postBuffer;
331  char* pPostBuffer;
333  size_t minPostBufferSize(const size_t size) { return std::min(size, size_t(postBuffer.get()+contentLength-pPostBuffer)); }
334  };
335 
337 
343  void charToString(const char* data, size_t size, std::wstring& string);
344 
346 
352  inline void charToString(const char* data, size_t size, std::string& string) { string.assign(data, size); }
353 
355 
365  int atoi(const char* start, const char* end);
366 
368 
375  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='&');
376 
378 
388  size_t percentEscapedToRealBytes(const char* source, char* destination, size_t size);
389 
393  extern const char base64Characters[];
394 
407  template<class In, class Out> void base64Encode(In start, In end, Out destination);
408 
425  template<class In, class Out> Out base64Decode(In start, In end, Out destination);
426 
430  class SessionId
431  {
435  public: static const int size=12;
436 
437  private:
441  char data[size];
442 
446  boost::posix_time::ptime timestamp;
447 
451  static bool seeded;
452 
453  template<class T> friend class Sessions;
454  public:
458  SessionId();
459 
460  SessionId(const SessionId& x): timestamp(x.timestamp) { std::memcpy(data, x.data, size); }
461  const SessionId& operator=(const SessionId& x) { std::memcpy(data, x.data, size); timestamp=x.timestamp; return *this; }
462 
470  template<class charT> const SessionId& operator=(charT* data_);
471 
479  template<class charT> SessionId(charT* data_) { *this=data_; }
480 
481  template<class charT, class Traits> friend std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const SessionId& x);
482 
483  bool operator<(const SessionId& x) const { return std::memcmp(data, x.data, SessionId::size)<0; }
484  bool operator==(const SessionId& x) const { return std::memcmp(data, x.data, SessionId::size)==0; }
485 
489  void refresh() const { *const_cast<boost::posix_time::ptime*>(&timestamp)=boost::posix_time::second_clock::universal_time(); }
490 
491  const char* getInternalPointer() const { return data; }
492  };
493 
497  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; }
498 
509  template<class T> class Sessions: public std::map<SessionId, T>
510  {
511  private:
515  const boost::posix_time::seconds keepAlive;
516 
520  const boost::posix_time::seconds cleanupFrequency;
521 
525  boost::posix_time::ptime cleanupTime;
526  public:
527  typedef typename std::map<SessionId, T>::iterator iterator;
528  typedef typename std::map<SessionId, T>::const_iterator const_iterator;
535  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) { }
536 
542  void cleanup();
543 
551  iterator generate(const T& value_ = T());
552 
553  boost::posix_time::ptime getExpiry(const_iterator it) const { return it->first.timestamp+keepAlive; }
554  };
555  }
556 }
557 
559 {
560  if(boost::posix_time::second_clock::universal_time() < cleanupTime)
561  return;
562  boost::posix_time::ptime oldest(boost::posix_time::second_clock::universal_time()-keepAlive);
563  iterator it=this->begin();
564  while(it!=this->end())
565  {
566  if(it->first.timestamp < oldest)
567  erase(it++);
568  else
569  ++it;
570  }
571  cleanupTime=boost::posix_time::second_clock::universal_time()+cleanupFrequency;
572 }
573 
574 template<class In, class Out> Out Fastcgipp::Http::base64Decode(In start, In end, Out destination)
575 {
576  Out dest=destination;
577 
578  for(int buffer, bitPos=-8, padStart; start!=end || bitPos>-6; ++dest)
579  {
580  if(bitPos==-8)
581  {
582  bitPos=18;
583  padStart=-9;
584  buffer=0;
585  while(bitPos!=-6)
586  {
587  if(start==end) return destination;
588  int value=*start++;
589  if(value >= 'A' && 'Z' >= value) value -= 'A';
590  else if(value >= 'a' && 'z' >= value) value -= 'a' - 26;
591  else if(value >= '0' && '9' >= value) value -= '0' - 52;
592  else if(value == '+') value = 62;
593  else if(value == '/') value = 63;
594  else if(value == '=') { padStart=bitPos; break; }
595  else return destination;
596 
597  buffer |= value << bitPos;
598  bitPos-=6;
599  }
600  bitPos=16;
601  }
602 
603  *dest = (buffer >> bitPos) & 0xff;
604  bitPos-=8;
605  if(padStart>=bitPos)
606  {
607  if( (padStart-bitPos)/6 )
608  return dest;
609  else
610  return ++dest;
611  }
612  }
613 
614  return dest;
615 }
616 
617 template<class In, class Out> void Fastcgipp::Http::base64Encode(In start, In end, Out destination)
618 {
619  for(int buffer, bitPos=-6, padded; start!=end || bitPos>-6; ++destination)
620  {
621  if(bitPos==-6)
622  {
623  bitPos=16;
624  buffer=0;
625  padded=-6;
626  while(bitPos!=-8)
627  {
628  if(start!=end)
629  buffer |= (uint32_t)*(unsigned char*)start++ << bitPos;
630  else padded+=6;
631  bitPos-=8;
632  }
633  bitPos=18;
634  }
635 
636  if(padded == bitPos)
637  {
638  *destination='=';
639  padded-=6;
640  }
641  else *destination=base64Characters[ (buffer >> bitPos)&0x3f ];
642  bitPos -= 6;
643  }
644 }
645 
647 {
648  std::pair<iterator,bool> retVal;
649  retVal.second=false;
650  while(!retVal.second)
651  retVal=insert(std::pair<SessionId, T>(SessionId(), value_));
652  return retVal.first;
653 }
654 
655 #endif