22 #include <boost/date_time/posix_time/posix_time.hpp>
27 #include "utf8_codecvt.hpp"
31 const size_t bufferSize=512;
32 wchar_t buffer[bufferSize];
37 codecvt_base::result cr=codecvt_base::partial;
38 while(cr==codecvt_base::partial)
42 mbstate_t conversionState = mbstate_t();
43 cr=use_facet<codecvt<wchar_t, char, mbstate_t> >(locale(locale::classic(),
new utf8CodeCvt::utf8_codecvt_facet)).in(conversionState, data, data+size, tmpData, buffer, buffer+bufferSize, it);
44 string.append(buffer, it);
61 for(; 0x30 <= *start && *start <= 0x39 && start<end; ++start)
62 result=result*10+(*start&0x0f);
64 return neg?-result:result;
69 if (size < 1)
return 0;
72 char* start=destination;
78 for(
int shift=4; shift>=0; shift-=4)
82 if((*source|0x20) >=
'a' && (*source|0x20) <=
'f')
83 *destination|=((*source|0x20)-0x57)<<shift;
84 else if(*source >=
'0' && *source <=
'9')
85 *destination|=(*source&0x0f)<<shift;
96 *destination++=*source++;
100 return destination-start;
108 using namespace boost;
117 size-=value-data+valueSize;
118 data=value+valueSize;
123 if(!memcmp(name,
"HTTP_HOST", 9))
125 else if(!memcmp(name,
"PATH_INFO", 9))
127 boost::scoped_array<char> buffer(
new char[valueSize]);
128 const char* source=value;
130 for(; source<value+valueSize+1; ++source, ++size)
132 if(*source ==
'/' || source == value+valueSize)
137 pathInfo.push_back(std::basic_string<charT>());
146 if(!memcmp(name,
"HTTP_ACCEPT", 11))
148 else if(!memcmp(name,
"HTTP_COOKIE", 11))
150 else if(!memcmp(name,
"SERVER_ADDR", 11))
151 serverAddress.assign(value, value+valueSize);
152 else if(!memcmp(name,
"REMOTE_ADDR", 11))
153 remoteAddress.assign(value, value+valueSize);
154 else if(!memcmp(name,
"SERVER_PORT", 11))
155 serverPort=
atoi(value, value+valueSize);
156 else if(!memcmp(name,
"REMOTE_PORT", 11))
157 remotePort=
atoi(value, value+valueSize);
158 else if(!memcmp(name,
"SCRIPT_NAME", 11))
160 else if(!memcmp(name,
"REQUEST_URI", 11))
164 if(!memcmp(name,
"HTTP_REFERER", 12) && valueSize)
166 else if(!memcmp(name,
"CONTENT_TYPE", 12))
168 const char* end=(
char*)memchr(value,
';', valueSize);
169 charToString(value, end?end-value:valueSize, contentType);
172 const char* start=(
char*)memchr(end,
'=', valueSize-(end-data));
175 boundarySize=valueSize-(++start-value);
176 boundary.reset(
new char[boundarySize]);
177 memcpy(boundary.get(), start, boundarySize);
181 else if(!memcmp(name,
"QUERY_STRING", 12) && valueSize)
185 if(!memcmp(name,
"DOCUMENT_ROOT", 13))
189 if(!memcmp(name,
"REQUEST_METHOD", 14))
214 else if(!memcmp(name,
"CONTENT_LENGTH", 14))
215 contentLength=
atoi(value, value+valueSize);
218 if(!memcmp(name,
"HTTP_USER_AGENT", 15))
220 else if(!memcmp(name,
"HTTP_KEEP_ALIVE", 15))
221 keepAlive=
atoi(value, value+valueSize);
224 if(!memcmp(name,
"HTTP_IF_NONE_MATCH", 18))
225 etag=
atoi(value, value+valueSize);
228 if(!memcmp(name,
"HTTP_ACCEPT_CHARSET", 19))
232 if(!memcmp(name,
"HTTP_ACCEPT_LANGUAGE", 20))
236 if(!memcmp(name,
"HTTP_IF_MODIFIED_SINCE", 22))
238 stringstream dateStream;
239 dateStream.write(value, valueSize);
240 dateStream.imbue(locale(locale::classic(),
new posix_time::time_input_facet(
"%a, %d %b %Y %H:%M:%S GMT")));
241 dateStream >> ifModifiedSince;
254 postBuffer.reset(
new char[contentLength]);
255 pPostBuffer=postBuffer.get();
258 size_t trueSize=minPostBufferSize(size);
261 std::memcpy(pPostBuffer, data, trueSize);
262 pPostBuffer+=trueSize;
275 const char cName[] =
"name=\"";
276 const char cFilename[] =
"filename=\"";
277 const char cContentType[] =
"Content-Type: ";
278 const char cBodyStart[] =
"\r\n\r\n";
280 pPostBuffer=postBuffer.get()+boundarySize+1;
281 const char* contentTypeStart=0;
282 ssize_t contentTypeSize=-1;
283 const char* nameStart=0;
285 const char* filenameStart=0;
286 ssize_t filenameSize=-1;
287 const char* bodyStart=0;
289 enum ParseState { HEADER, NAME, FILENAME, CONTENT_TYPE, BODY } parseState=HEADER;
290 for(pPostBuffer=postBuffer.get()+boundarySize+2; pPostBuffer<postBuffer.get()+contentLength; ++pPostBuffer)
298 const size_t size=minPostBufferSize(
sizeof(cName)-1);
299 if(!memcmp(pPostBuffer, cName, size))
302 nameStart=pPostBuffer+1;
307 if(filenameSize == -1)
309 const size_t size=minPostBufferSize(
sizeof(cFilename)-1);
310 if(!memcmp(pPostBuffer, cFilename, size))
313 filenameStart=pPostBuffer+1;
318 if(contentTypeSize == -1)
320 const size_t size=minPostBufferSize(
sizeof(cContentType)-1);
321 if(!memcmp(pPostBuffer, cContentType, size))
324 contentTypeStart=pPostBuffer+1;
325 parseState=CONTENT_TYPE;
331 const size_t size=minPostBufferSize(
sizeof(cBodyStart)-1);
332 if(!memcmp(pPostBuffer, cBodyStart, size))
335 bodyStart=pPostBuffer+1;
345 if(*pPostBuffer ==
'"')
347 nameSize=pPostBuffer-nameStart;
355 if(*pPostBuffer ==
'"')
357 filenameSize=pPostBuffer-filenameStart;
365 if(*pPostBuffer ==
'\r' || *pPostBuffer ==
'\n')
367 contentTypeSize=pPostBuffer-contentTypeStart;
376 const size_t size=minPostBufferSize(
sizeof(boundarySize)-1);
377 if(!memcmp(pPostBuffer, boundary.get(), size))
379 bodySize=pPostBuffer-bodyStart-2;
380 if(bodySize<0) bodySize=0;
381 else if(bodySize>=2 && *(bodyStart+bodySize-1)==
'\n' && *(bodyStart+bodySize-2)==
'\r')
386 basic_string<charT> name;
390 if(contentTypeSize != -1)
398 thePost.
m_data =
new char[bodySize];
399 memcpy(thePost.
m_data, bodyStart, bodySize);
430 char* nameStart=postBuffer.get();
435 for(
char* i=postBuffer.get(); i<=postBuffer.get()+contentLength; ++i)
437 if(*i ==
'=' && nameStart && !valueStart)
442 else if( (i==postBuffer.get()+contentLength || *i ==
'&') && nameStart && valueStart)
446 std::basic_string<charT> name;
463 std::srand(boost::posix_time::microsec_clock::universal_time().time_of_day().fractional_seconds());
467 for(
char* i=data; i<data+size; ++i)
469 timestamp = boost::posix_time::second_clock::universal_time();
476 std::memset(data, 0, size);
478 timestamp = boost::posix_time::second_clock::universal_time();
482 template void Fastcgipp::Http::decodeUrlEncoded<char>(
const char* data,
size_t size, std::map<std::basic_string<char>, std::basic_string<char> >& output,
const char fieldSeperator);
483 template void Fastcgipp::Http::decodeUrlEncoded<wchar_t>(
const char* data,
size_t size, std::map<std::basic_string<wchar_t>, std::basic_string<wchar_t> >& output,
const char fieldSeperator);
484 template<
class charT>
void Fastcgipp::Http::decodeUrlEncoded(
const char* data,
size_t size, std::map<std::basic_string<charT>, std::basic_string<charT> >& output,
const char fieldSeperator)
488 boost::scoped_array<char> buffer(
new char[size]);
489 memcpy(buffer.get(), data, size);
491 char* nameStart=buffer.get();
495 for(
char* i=buffer.get(); i<=buffer.get()+size; ++i)
497 if(i==buffer.get()+size || *i == fieldSeperator)
499 if(nameStart && valueStart)
503 basic_string<charT> name;
506 basic_string<charT>& value=output[name];
512 else if(*i ==
' ' && nameStart && !valueStart)
515 else if(*i ==
'=' && nameStart && !valueStart)
540 static const std::basic_string<charT> emptyString;
541 typename Cookies::const_iterator it=cookies.find(key);
542 if(it==cookies.end())
552 static const std::basic_string<charT> emptyString;
553 typename Gets::const_iterator it=gets.find(key);
565 typename Posts::const_iterator it=posts.find(key);
576 typename Gets::const_iterator it=gets.find(key);
587 typename Posts::const_iterator it=posts.find(key);
596 *(uint64_t*)m_data &= *(
const uint64_t*)x.
m_data;
597 *(uint64_t*)(m_data+size/2) &= *(
const uint64_t*)(x.
m_data+size/2);
612 const char* read=start-1;
613 unsigned char* write=m_data;
614 unsigned char* pad=0;
615 unsigned char offset;
622 if(read >= end || *read ==
':')
624 if(read == start || *(read-1) ==
':')
626 if(pad && pad != write)
636 *write = (chunk&0xff00)>>8;
637 *(write+1) = chunk&0x00ff;
640 if(write>=m_data+size || read >= end)
645 else if(
'0' <= *read && *read <=
'9')
647 else if(
'A' <= *read && *read <=
'F')
649 else if(
'a' <= *read && *read <=
'f')
651 else if(*read ==
'.')
656 *(uint16_t*)write = 0xffff;
660 else if(write - m_data > 12)
669 for(
int i=0; i<3; ++i)
671 *write = *write * 10 + ((chunk&0x0f00)>>8);
677 for(
int i=0; i<3 && read<end; ++i)
679 const char* point=(
const char*)memchr(read,
'.', end-read);
680 if(point && point<end-1)
687 *write++ =
atoi(++read, end);
697 chunk |= *read-offset;
701 std::memset(m_data, 0, size);
705 std::memset(write, 0, size-(write-m_data));
708 const size_t padSize=m_data+size-write;
709 std::memmove(pad+padSize, pad, write-pad);
710 std::memset(pad, 0, padSize);
715 template std::basic_ostream<char, std::char_traits<char> >& Fastcgipp::Http::operator<< <char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >& os,
const Address& address);
716 template std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& Fastcgipp::Http::operator<< <wchar_t, std::char_traits<wchar_t> >(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& os,
const Address& address);
717 template<
class charT,
class Traits> std::basic_ostream<charT, Traits>& Fastcgipp::Http::operator<<(std::basic_ostream<charT, Traits>& os,
const Address& address)
720 if(!os.good())
return os;
724 typename basic_ostream<charT, Traits>::sentry opfx(os);
727 streamsize fieldWidth=os.width(0);
729 charT* bufPtr=buffer;
730 locale loc(os.getloc(),
new num_put<charT, charT*>);
732 const uint16_t* subStart=0;
733 const uint16_t* subEnd=0;
735 const uint16_t* subStartCandidate;
736 const uint16_t* subEndCandidate;
739 for(
const uint16_t* it = (
const uint16_t*)address.data(); it < (
const uint16_t*)(address.data()+Address::size); ++it)
745 subStartCandidate = it;
746 subEndCandidate = it;
753 if(subEndCandidate-subStartCandidate > subEnd-subStart)
755 subStart=subStartCandidate;
756 subEnd=subEndCandidate-1;
763 if(subEndCandidate-subStartCandidate > subEnd-subStart)
765 subStart=subStartCandidate;
766 subEnd=subEndCandidate-1;
772 ios_base::fmtflags oldFlags = os.flags();
773 os.setf(ios::hex, ios::basefield);
775 if(subStart==(
const uint16_t*)address.data() && subEnd==(
const uint16_t*)address.data()+4 && *((
const uint16_t*)address.data()+5) == 0xffff)
778 *bufPtr++=os.widen(
':');
779 *bufPtr++=os.widen(
':');
780 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(bufPtr, os, os.fill(),
static_cast<unsigned long int>(0xffff));
781 *bufPtr++=os.widen(
':');
782 os.setf(ios::dec, ios::basefield);
784 for(
const unsigned char* it = address.data()+12; it < address.data()+Address::size; ++it)
786 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(bufPtr, os, os.fill(),
static_cast<unsigned long int>(*it));
787 *bufPtr++=os.widen(
'.');
794 for(
const uint16_t* it = (
const uint16_t*)address.data(); it < (
const uint16_t*)(address.data()+Address::size); ++it)
796 if(subStart <= it && it <= subEnd)
798 if(it == subStart && it == (
const uint16_t*)address.data())
799 *bufPtr++=os.widen(
':');
801 *bufPtr++=os.widen(
':');
805 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(bufPtr, os, os.fill(),
static_cast<unsigned long int>(
Protocol::readBigEndian(*it)));
807 if(it < (
const uint16_t*)(address.data()+Address::size)-1)
808 *bufPtr++=os.widen(
':');
816 ostreambuf_iterator<charT,Traits> sink(os);
817 if(os.flags() & ios_base::left)
818 for(
int i=max(fieldWidth, bufPtr-buffer); i>0; i--)
820 if(ptr!=bufPtr) *sink++=*ptr++;
821 else *sink++=os.fill();
824 for(
int i=fieldWidth-(bufPtr-buffer); ptr!=bufPtr;)
826 if(i>0) { *sink++=os.fill(); --i; }
830 if(sink.failed()) os.setstate(ios_base::failbit);
835 ios_base::iostate exception_mask = os.exceptions();
836 os.exceptions(ios_base::goodbit);
837 os.setstate(ios_base::badbit);
838 os.exceptions(exception_mask);
839 if(exception_mask & ios_base::badbit)
throw;
843 ios_base::iostate exception_mask = os.exceptions();
844 os.exceptions(ios_base::goodbit);
845 os.setstate(ios_base::failbit);
846 os.exceptions(exception_mask);
847 if(exception_mask & ios_base::failbit)
throw;
852 template std::basic_istream<char, std::char_traits<char> >& Fastcgipp::Http::operator>> <char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >& is, Address& address);
853 template std::basic_istream<wchar_t, std::char_traits<wchar_t> >& Fastcgipp::Http::operator>> <wchar_t, std::char_traits<wchar_t> >(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& is, Address& address);
857 if(!is.good())
return is;
859 ios_base::iostate err = ios::goodbit;
862 typename basic_istream<charT, Traits>::sentry ipfx(is);
865 istreambuf_iterator<charT, Traits> read(is);
866 unsigned char buffer[Address::size];
867 unsigned char* write=buffer;
868 unsigned char* pad=0;
869 unsigned char offset;
870 unsigned char count=0;
881 else if(
'0' <= *read && *read <=
'9')
883 else if(
'A' <= *read && *read <=
'F')
885 else if(
'a' <= *read && *read <=
'f')
887 else if(*read ==
'.')
892 *(uint16_t*)write = 0xffff;
896 else if(write - buffer > 12)
905 for(
int i=0; i<3; ++i)
907 *write = *write * 10 + ((chunk&0x0f00)>>8);
913 for(
int i=0; i<3; ++i)
915 if(*read != is.widen(
'.'))
921 use_facet<num_get<charT, istreambuf_iterator<charT, Traits> > >(is.getloc()).
get(++read, istreambuf_iterator<charT, Traits>(), is, err, value);
928 if(*read ==
':' && (!lastChar || lastChar ==
':'))
930 if(pad && pad != write)
940 *write = (chunk&0xff00)>>8;
941 *(write+1) = chunk&0x00ff;
944 if(write>=buffer+Address::size)
957 chunk |= *read-offset;
962 if(err == ios::goodbit)
967 std::memset(write, 0, Address::size-(write-buffer));
970 const size_t padSize=buffer+Address::size-write;
971 std::memmove(pad+padSize, pad, write-pad);
972 std::memset(pad, 0, padSize);
983 ios_base::iostate exception_mask = is.exceptions();
984 is.exceptions(ios_base::goodbit);
985 is.setstate(ios_base::badbit);
986 is.exceptions(exception_mask);
987 if(exception_mask & ios_base::badbit)
throw;
991 ios_base::iostate exception_mask = is.exceptions();
992 is.exceptions(ios_base::goodbit);
993 is.setstate(ios_base::failbit);
994 is.exceptions(exception_mask);
995 if(exception_mask & ios_base::failbit)
throw;
1001 Fastcgipp::Http::Address::operator bool()
const
1003 static const unsigned char nullString[size] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1004 if(std::memcmp(m_data, nullString, size) == 0)