45 std::wstring_convert<std::codecvt_utf8<wchar_t>,
wchar_t> converter;
48 string = converter.from_bytes(&*start, &*end);
50 catch(
const std::range_error& e)
56 template int Fastcgipp::Http::atoi<char>(
const char* start,
const char* end);
57 template int Fastcgipp::Http::atoi<wchar_t>(
70 for(; 0x30 <= *start && *start <= 0x39 && start<end; ++start)
71 result=result*10+(*start&0x0f);
73 return neg?-result:result;
76 template float Fastcgipp::Http::atof<char>(
const char* start,
const char* end);
77 template float Fastcgipp::Http::atof<wchar_t>(
96 if(0x30 <= *start && *start <= 0x39)
99 result = result*10+(*start&0x0f);
102 result += (*start&0x0f)*multiplier;
106 else if(*start ==
'.')
113 return neg?-result:result;
135 state = DECODINGFIRST;
140 *destination++=*start;
142 else if(state == DECODINGFIRST)
144 if((*start|0x20) >=
'a' && (*start|0x20) <=
'f')
145 *destination = ((*start|0x20)-0x57)<<4;
146 else if(*start >=
'0' && *start <=
'9')
147 *destination = (*start&0x0f)<<4;
149 state = DECODINGSECOND;
151 else if(state == DECODINGSECOND)
153 if((*start|0x20) >=
'a' && (*start|0x20) <=
'f')
154 *destination |= (*start|0x20)-0x57;
155 else if(*start >=
'0' && *start <=
'9')
156 *destination |= *start&0x0f;
168 const char*
const dataEnd)
184 if(std::equal(name, value,
"HTTP_HOST"))
186 else if(std::equal(name, value,
"PATH_INFO"))
188 const size_t bufferSize = end-value;
189 std::unique_ptr<char[]> buffer(
new char[bufferSize]);
196 if(*source ==
'/' || source == end)
204 pathInfo.push_back(std::basic_string<charT>());
216 if(std::equal(name, value,
"HTTP_ACCEPT"))
218 else if(std::equal(name, value,
"HTTP_COOKIE"))
220 else if(std::equal(name, value,
"SERVER_ADDR"))
221 serverAddress.assign(&*value, &*end);
222 else if(std::equal(name, value,
"REMOTE_ADDR"))
223 remoteAddress.assign(&*value, &*end);
224 else if(std::equal(name, value,
"SERVER_PORT"))
225 serverPort=
atoi(&*value, &*end);
226 else if(std::equal(name, value,
"REMOTE_PORT"))
227 remotePort=
atoi(&*value, &*end);
228 else if(std::equal(name, value,
"SCRIPT_NAME"))
230 else if(std::equal(name, value,
"REQUEST_URI"))
234 if(std::equal(name, value,
"HTTP_REFERER"))
236 else if(std::equal(name, value,
"CONTENT_TYPE"))
238 const auto semicolon = std::find(value, end,
';');
245 const auto equals = std::find(semicolon, end,
'=');
252 else if(std::equal(name, value,
"QUERY_STRING"))
256 if(std::equal(name, value,
"DOCUMENT_ROOT"))
260 if(std::equal(name, value,
"REQUEST_METHOD"))
270 RequestMethod::GET)]))
271 requestMethod = RequestMethod::GET;
276 RequestMethod::PUT)]))
277 requestMethod = RequestMethod::PUT;
284 RequestMethod::HEAD)]))
285 requestMethod = RequestMethod::HEAD;
290 RequestMethod::POST)]))
291 requestMethod = RequestMethod::POST;
298 RequestMethod::TRACE)]))
299 requestMethod = RequestMethod::TRACE;
306 RequestMethod::DELETE)]))
307 requestMethod = RequestMethod::DELETE;
314 RequestMethod::OPTIONS)]))
315 requestMethod = RequestMethod::OPTIONS;
320 RequestMethod::OPTIONS)]))
321 requestMethod = RequestMethod::CONNECT;
325 else if(std::equal(name, value,
"CONTENT_LENGTH"))
326 contentLength=
atoi(&*value, &*end);
329 if(std::equal(name, value,
"HTTP_USER_AGENT"))
331 else if(std::equal(name, value,
"HTTP_KEEP_ALIVE"))
332 keepAlive=
atoi(&*value, &*end);
335 if(std::equal(name, value,
"HTTP_IF_NONE_MATCH"))
336 etag=
atoi(&*value, &*end);
337 else if(std::equal(name, value,
"HTTP_AUTHORIZATION"))
341 if(std::equal(name, value,
"HTTP_ACCEPT_CHARSET"))
345 if(std::equal(name, value,
"HTTP_ACCEPT_LANGUAGE"))
347 const char* groupStart = value;
348 const char* groupEnd;
349 const char* subStart;
352 while(groupStart < end)
354 acceptLanguages.push_back(std::string());
355 std::string& language = acceptLanguages.back();
357 groupEnd = std::find(groupStart, end,
',');
360 subEnd = std::find(groupStart, groupEnd,
';');
361 subStart = groupStart;
362 while(subStart != subEnd && *subStart ==
' ')
364 while(subEnd != subStart && *(subEnd-1) ==
' ')
368 dash = language.find(
'-');
369 if(dash != std::string::npos)
370 language[dash] =
'_';
372 groupStart = groupEnd+1;
377 if(std::equal(name, value,
"HTTP_IF_MODIFIED_SINCE"))
381 reinterpret_cast<char*>(&time),
382 reinterpret_cast<char*>(&time)+
sizeof(time),
384 std::stringstream dateStream;
385 dateStream.write(&*value, end-value);
386 dateStream >> std::get_time(
388 "%a, %d %b %Y %H:%M:%S GMT");
389 ifModifiedSince = std::mktime(&time) - timezone;
397 template<
class charT>
399 const char*
const start,
400 const char*
const end)
402 if(m_postBuffer.empty())
403 m_postBuffer.reserve(contentLength);
404 m_postBuffer.insert(m_postBuffer.end(), start, end);
407 template<
class charT>
410 static const std::string multipartStr(
"multipart/form-data");
411 static const std::string urlEncodedStr(
"application/x-www-form-urlencoded");
413 if(!m_postBuffer.size())
419 multipartStr.cbegin(),
421 contentType.cbegin(),
424 parsePostsMultipart();
428 urlEncodedStr.cbegin(),
429 urlEncodedStr.cend(),
430 contentType.cbegin(),
433 parsePostsUrlEncoded();
440 template<
class charT>
443 static const std::string cName(
"name=\"");
444 static const std::string cFilename(
"filename=\"");
445 static const std::string cContentType(
"Content-Type: ");
446 static const std::string cBody(
"\r\n\r\n");
448 const char*
const postBufferStart = m_postBuffer.data();
449 const char*
const postBufferEnd = m_postBuffer.data() + m_postBuffer.size();
451 auto nameStart(postBufferEnd);
452 auto nameEnd(postBufferEnd);
453 auto filenameStart(postBufferEnd);
454 auto filenameEnd(postBufferEnd);
455 auto contentTypeStart(postBufferEnd);
456 auto contentTypeEnd(postBufferEnd);
457 auto bodyStart(postBufferEnd);
458 auto bodyEnd(postBufferEnd);
469 for(
auto byte = postBufferStart; byte < postBufferEnd; ++byte)
475 const size_t bytesLeft = size_t(postBufferEnd-byte);
478 nameEnd == postBufferEnd &&
479 bytesLeft >= cName.size() &&
480 std::equal(cName.begin(), cName.end(), byte))
482 byte += cName.size()-1;
487 filenameEnd == postBufferEnd &&
488 bytesLeft >= cFilename.size() &&
489 std::equal(cFilename.begin(), cFilename.end(), byte))
491 byte += cFilename.size()-1;
492 filenameStart = byte+1;
496 contentTypeEnd == postBufferEnd &&
497 bytesLeft >= cContentType.size() &&
498 std::equal(cContentType.begin(), cContentType.end(), byte))
500 byte += cContentType.size()-1;
501 contentTypeStart = byte+1;
502 state = CONTENT_TYPE;
505 bodyEnd == postBufferEnd &&
506 bytesLeft >= cBody.size() &&
507 std::equal(cBody.begin(), cBody.end(), byte))
509 byte += cBody.size()-1;
539 if(*byte ==
'\r' || *byte ==
'\n')
541 contentTypeEnd = byte--;
549 const size_t bytesLeft = size_t(postBufferEnd-byte);
552 bytesLeft >= boundary.size() &&
553 std::equal(boundary.begin(), boundary.end(), byte))
556 if(bodyEnd<bodyStart)
560 && *(bodyEnd-1)==
'\n' 561 && *(bodyEnd-2)==
'\r')
564 if(nameEnd != postBufferEnd)
566 std::basic_string<charT> name;
569 if(contentTypeEnd != postBufferEnd)
576 if(filenameEnd != postBufferEnd)
582 file.
size = bodyEnd-bodyStart;
583 file.
data.reset(
new char[file.
size]);
584 std::copy(bodyStart, bodyEnd, file.
data.get());
586 files.insert(std::make_pair(
592 std::basic_string<charT> value;
594 posts.insert(std::make_pair(
601 nameStart = postBufferEnd;
602 nameEnd = postBufferEnd;
603 filenameStart = postBufferEnd;
604 filenameEnd = postBufferEnd;
605 contentTypeStart = postBufferEnd;
606 contentTypeEnd = postBufferEnd;
607 bodyStart = postBufferEnd;
608 bodyEnd = postBufferEnd;
617 template<
class charT>
622 m_postBuffer.data()+m_postBuffer.size(),
631 std::random_device device;
632 std::uniform_int_distribution<unsigned short> distribution(0, 255);
634 for(
unsigned char& byte:
m_data)
635 byte =
static_cast<unsigned char>(distribution(device));
640 const std::basic_string<char>&
string);
642 const std::basic_string<wchar_t>&
string);
644 const std::basic_string<charT>&
string)
648 string.begin()+std::min(stringLength,
string.size()),
650 m_timestamp = std::time(
nullptr);
656 template void Fastcgipp::Http::decodeUrlEncoded<char>(
658 const char*
const dataEnd,
660 std::basic_string<char>,
661 std::basic_string<char>>& output,
662 const char*
const fieldSeparator);
663 template void Fastcgipp::Http::decodeUrlEncoded<wchar_t>(
665 const char*
const dataEnd,
667 std::basic_string<wchar_t>,
668 std::basic_string<wchar_t>>& output,
669 const char*
const fieldSeparator);
672 const char*
const dataEnd,
674 std::basic_string<charT>,
675 std::basic_string<charT>>& output,
676 const char*
const fieldSeparator)
678 std::unique_ptr<char[]> buffer(
new char[dataEnd-data]);
679 std::basic_string<charT> name;
680 std::basic_string<charT> value;
682 const size_t fieldSeparatorSize = std::strlen(fieldSeparator);
683 const char*
const fieldSeparatorEnd = fieldSeparator+fieldSeparatorSize;
693 auto nameStart(data);
694 auto nameEnd(dataEnd);
695 auto valueStart(dataEnd);
696 auto valueEnd(dataEnd);
698 while(data < dataEnd)
700 if(nameEnd != dataEnd)
702 if(data+1 == dataEnd)
707 else if(data+fieldSeparatorSize<=dataEnd
708 && std::equal(fieldSeparator, fieldSeparatorEnd, data))
710 endState = SEPARATOR;
724 output.insert(std::make_pair(
728 nameStart = data+fieldSeparatorSize;
729 data += fieldSeparatorSize-1;
731 valueStart = dataEnd;
753 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
754 'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
755 'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
'4',
756 '5',
'6',
'7',
'8',
'9',
'+',
'/' 775 *
reinterpret_cast<uint64_t*
>(m_data.data())
776 &= *reinterpret_cast<const uint64_t*>(x.m_data.data());
777 *
reinterpret_cast<uint64_t*
>(m_data.data()+8)
778 &= *reinterpret_cast<const uint64_t*>(x.m_data.data()+8);
784 const Address& x)
const 786 Address address(*
this);
792 template void Fastcgipp::Http::Address::assign<char>(
795 template void Fastcgipp::Http::Address::assign<wchar_t>(
796 const wchar_t* start,
802 const charT* read=start-1;
803 auto write=m_data.begin();
804 auto pad=m_data.end();
805 unsigned char offset;
812 if(read >= end || *read ==
':')
814 if(read == start || *(read-1) ==
':')
816 if(pad!=m_data.end() && pad!=write)
826 *write = (chunk&0xff00)>>8;
827 *(write+1) = chunk&0x00ff;
830 if(write>=m_data.end() || read>=end)
832 if(read>=end && write<m_data.end() && pad==m_data.end())
839 else if(
'0' <= *read && *read <=
'9')
841 else if(
'A' <= *read && *read <=
'F')
843 else if(
'a' <= *read && *read <=
'f')
845 else if(*read ==
'.')
847 if(write == m_data.begin())
851 *
reinterpret_cast<uint16_t*
>(write) = 0xffff;
852 pad = m_data.begin();
855 else if(write - m_data.begin() > 12)
865 for(
int i=0; i<3; ++i)
867 *write = *write * 10 + ((chunk&0x0f00)>>8);
873 for(
int i=0; i<3 && read<end; ++i)
875 const charT* point=std::find(read, end,
'.');
883 *write++ =
atoi(++read, end);
893 chunk |= *read-offset;
900 << std::wstring(start, end))
902 else if(pad != m_data.end())
905 std::fill(write, m_data.end(), 0);
908 auto padEnd=pad+(m_data.end()-write);
909 std::copy(pad, write, padEnd);
910 std::fill(pad, padEnd, 0);
915 template std::basic_ostream<char, std::char_traits<char>>&
916 Fastcgipp::Http::operator<< <char, std::char_traits<char>>(
917 std::basic_ostream<char, std::char_traits<char>>& os,
919 template std::basic_ostream<wchar_t, std::char_traits<wchar_t>>&
920 Fastcgipp::Http::operator<< <wchar_t, std::char_traits<wchar_t>>(
921 std::basic_ostream<wchar_t, std::char_traits<wchar_t>>& os,
923 template<
class charT,
class Traits> std::basic_ostream<charT, Traits>&
925 std::basic_ostream<charT, Traits>& os,
929 if(!os.good())
return os;
933 typename basic_ostream<charT, Traits>::sentry opfx(os);
936 streamsize fieldWidth=os.width(0);
938 charT* bufPtr=buffer;
939 locale loc(os.getloc(),
new num_put<charT, charT*>);
941 const uint16_t* subStart=0;
942 const uint16_t* subEnd=0;
944 const uint16_t* subStartCandidate;
945 const uint16_t* subEndCandidate;
949 const uint16_t* it = reinterpret_cast<const uint16_t*>(
951 it < reinterpret_cast<const uint16_t*>(
959 subStartCandidate = it;
960 subEndCandidate = it;
967 if(subEndCandidate-subStartCandidate > subEnd-subStart)
969 subStart=subStartCandidate;
970 subEnd=subEndCandidate-1;
977 if(subEndCandidate-subStartCandidate > subEnd-subStart)
979 subStart=subStartCandidate;
980 subEnd=subEndCandidate-1;
986 ios_base::fmtflags oldFlags = os.flags();
987 os.setf(ios::hex, ios::basefield);
990 subStart==reinterpret_cast<const uint16_t*>(
992 && subEnd==reinterpret_cast<const uint16_t*>(
994 && *(reinterpret_cast<const uint16_t*>(
995 address.
m_data.data())+5) == 0xffff)
998 *bufPtr++=os.widen(
':');
999 *bufPtr++=os.widen(
':');
1000 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(
1004 static_cast<unsigned long int>(0xffff));
1005 *bufPtr++=os.widen(
':');
1006 os.setf(ios::dec, ios::basefield);
1009 const unsigned char* it = address.
m_data.data()+12;
1013 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(
1017 static_cast<unsigned long int>(*it));
1018 *bufPtr++=os.widen(
'.');
1025 for(
const uint16_t* it= reinterpret_cast<const uint16_t*>(
1027 it < reinterpret_cast<const uint16_t*>(
1031 if(subStart <= it && it <= subEnd)
1035 && it == reinterpret_cast<const uint16_t*>(
1037 *bufPtr++=os.widen(
':');
1039 *bufPtr++=os.widen(
':');
1043 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(
1047 static_cast<unsigned long int>(
1051 if(it < reinterpret_cast<const uint16_t*>(
1053 *bufPtr++=os.widen(
':');
1061 ostreambuf_iterator<charT,Traits> sink(os);
1062 if(os.flags() & ios_base::left)
1063 for(
int i=max(fieldWidth, bufPtr-buffer); i>0; i--)
1065 if(ptr!=bufPtr) *sink++=*ptr++;
1066 else *sink++=os.fill();
1069 for(
int i=fieldWidth-(bufPtr-buffer); ptr!=bufPtr;)
1071 if(i>0) { *sink++=os.fill(); --i; }
1072 else *sink++=*ptr++;
1075 if(sink.failed()) os.setstate(ios_base::failbit);
1080 ios_base::iostate exception_mask = os.exceptions();
1081 os.exceptions(ios_base::goodbit);
1082 os.setstate(ios_base::badbit);
1083 os.exceptions(exception_mask);
1084 if(exception_mask & ios_base::badbit)
throw;
1088 ios_base::iostate exception_mask = os.exceptions();
1089 os.exceptions(ios_base::goodbit);
1090 os.setstate(ios_base::failbit);
1091 os.exceptions(exception_mask);
1092 if(exception_mask & ios_base::failbit)
throw;
1097 template std::basic_istream<char, std::char_traits<char>>&
1098 Fastcgipp::Http::operator>> <char, std::char_traits<char>>(
1099 std::basic_istream<char, std::char_traits<char>>& is,
1101 template std::basic_istream<wchar_t, std::char_traits<wchar_t>>&
1102 Fastcgipp::Http::operator>> <wchar_t, std::char_traits<wchar_t>>(
1103 std::basic_istream<wchar_t, std::char_traits<wchar_t>>& is,
1105 template<
class charT,
class Traits> std::basic_istream<charT, Traits>&
1107 std::basic_istream<charT, Traits>& is,
1110 using namespace std;
1111 if(!is.good())
return is;
1113 ios_base::iostate err = ios::goodbit;
1116 typename basic_istream<charT, Traits>::sentry ipfx(is);
1119 istreambuf_iterator<charT, Traits> read(is);
1121 unsigned char* write=buffer;
1122 unsigned char* pad=0;
1123 unsigned char offset;
1124 unsigned char count=0;
1135 else if(
'0' <= *read && *read <=
'9')
1137 else if(
'A' <= *read && *read <=
'F')
1139 else if(
'a' <= *read && *read <=
'f')
1141 else if(*read ==
'.')
1146 *
reinterpret_cast<uint16_t*
>(write) = 0xffff;
1150 else if(write - buffer > 12)
1159 for(
int i=0; i<3; ++i)
1161 *write = *write * 10 + ((chunk&0x0f00)>>8);
1167 for(
int i=0; i<3; ++i)
1169 if(*read != is.widen(
'.'))
1175 use_facet<num_get<charT, istreambuf_iterator<charT, Traits> > >(is.getloc()).
get(++read, istreambuf_iterator<charT, Traits>(), is, err, value);
1182 if(*read ==
':' && (!lastChar || lastChar ==
':'))
1184 if(pad && pad != write)
1194 *write = (chunk&0xff00)>>8;
1195 *(write+1) = chunk&0x00ff;
1211 chunk |= *read-offset;
1216 if(err == ios::goodbit)
1225 std::memmove(pad+padSize, pad, write-pad);
1226 std::memset(pad, 0, padSize);
1237 ios_base::iostate exception_mask = is.exceptions();
1238 is.exceptions(ios_base::goodbit);
1239 is.setstate(ios_base::badbit);
1240 is.exceptions(exception_mask);
1241 if(exception_mask & ios_base::badbit)
throw;
1245 ios_base::iostate exception_mask = is.exceptions();
1246 is.exceptions(ios_base::goodbit);
1247 is.setstate(ios_base::failbit);
1248 is.exceptions(exception_mask);
1249 if(exception_mask & ios_base::failbit)
throw;
1255 Fastcgipp::Http::Address::operator bool()
const 1257 static const std::array<const unsigned char, 16> nullString =
1258 {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
1259 if(std::equal(m_data.begin(), m_data.end(), nullString.begin()))
float atof(const charT *start, const charT *end)
Convert a char string to a float.
std::array< unsigned char, size > m_data
Data representation of the IPv6 address.
std::basic_string< charT > filename
Filename.
Address operator &(const Address &x) const
void assign(const charT *start, const charT *end)
Assign the IP address from a string of characters.
std::basic_istream< charT, Traits > & operator>>(std::basic_istream< charT, Traits > &is, Address &address)
Address stream extractor operation.
bool processParamHeader(const char *data, const char *const dataEnd, const char *&name, const char *&value, const char *&end)
Process the body of a FastCGI record of type RecordType::PARAMS.
bool parsePostBuffer()
Attempts to parse the POST buffer.
void fillPostBuffer(const char *start, const char *end)
Consolidates POST data into a single buffer.
Holds a file uploaded from the client.
void parsePostsUrlEncoded()
Parses "application/x-www-form-urlencoded" post data.
std::time_t m_timestamp
Contains the time this session was last used.
char * percentEscapedToRealBytes(const char *start, const char *end, char *destination)
Convert a string with percent escaped byte values to their values.
std::array< unsigned char, size > m_data
ID data.
Declares elements of the HTTP protocol.
const std::array< const char *const, 9 > requestMethodLabels
Some textual labels for RequestMethod.
void vecToString(const char *start, const char *end, std::wstring &string)
Convert a char array to a std::wstring.
std::unique_ptr< char[]> data
File data.
int atoi(const charT *start, const charT *end)
Convert a char string to an integer.
void decodeUrlEncoded(const char *data, const char *dataEnd, std::multimap< std::basic_string< charT >, std::basic_string< charT >> &output, const char *const fieldSeparator="&")
Decodes a url-encoded string into a multimap container.
Data structure of HTTP environment data.
Out base64Decode(In start, In end, Out destination)
Convert a Base64 encoded container to a binary container.
void fill(const char *data, const char *dataEnd)
Parses FastCGI parameter data into the data structure.
static const size_t stringLength
Size in characters of string representation.
static const size_t size
Size in bytes of the ID data. Make sure it is a multiple of 3.
std::basic_ostream< charT, Traits > & operator<<(std::basic_ostream< charT, Traits > &os, const RequestMethod requestMethod)
static const size_t size
This is the data length of the IPv6 address.
std::basic_string< charT > contentType
Content Type.
void parsePostsMultipart()
Parses "multipart/form-data" http post data.
Address & operator &=(const Address &x)
const std::array< const char, 64 > base64Characters
List of characters in order for Base64 encoding.
Efficiently stores IPv6 addresses.
SessionId()
This constructor initializes the ID data to a random value.
Declares the Fastcgipp debugging/logging facilities.
#define WARNING_LOG(data)
Log any externally caused "errors".