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 #include <boost/date_time/posix_time/posix_time.hpp> 00023 00024 #include <fastcgi++/http.hpp> 00025 #include <fastcgi++/protocol.hpp> 00026 00027 #include "utf8_codecvt.hpp" 00028 00029 void Fastcgipp::Http::charToString(const char* data, size_t size, std::wstring& string) 00030 { 00031 const size_t bufferSize=512; 00032 wchar_t buffer[bufferSize]; 00033 using namespace std; 00034 00035 if(size) 00036 { 00037 codecvt_base::result cr=codecvt_base::partial; 00038 while(cr==codecvt_base::partial) 00039 {{ 00040 wchar_t* it; 00041 const char* tmpData; 00042 mbstate_t conversionState = mbstate_t(); 00043 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); 00044 string.append(buffer, it); 00045 size-=tmpData-data; 00046 data=tmpData; 00047 }} 00048 if(cr==codecvt_base::error) throw Exceptions::CodeCvt(); 00049 } 00050 } 00051 00052 int Fastcgipp::Http::atoi(const char* start, const char* end) 00053 { 00054 bool neg=false; 00055 if(*start=='-') 00056 { 00057 neg=true; 00058 ++start; 00059 } 00060 int result=0; 00061 for(; 0x30 <= *start && *start <= 0x39 && start<end; ++start) 00062 result=result*10+(*start&0x0f); 00063 00064 return neg?-result:result; 00065 } 00066 00067 size_t Fastcgipp::Http::percentEscapedToRealBytes(const char* source, char* destination, size_t size) 00068 { 00069 if (size < 1) return 0; 00070 00071 unsigned int i=0; 00072 char* start=destination; 00073 while(1) 00074 { 00075 if(*source=='%') 00076 { 00077 *destination=0; 00078 for(int shift=4; shift>=0; shift-=4) 00079 { 00080 if(++i>=size) break; 00081 ++source; 00082 if((*source|0x20) >= 'a' && (*source|0x20) <= 'f') 00083 *destination|=((*source|0x20)-0x57)<<shift; 00084 else if(*source >= '0' && *source <= '9') 00085 *destination|=(*source&0x0f)<<shift; 00086 } 00087 ++source; 00088 ++destination; 00089 } 00090 else if(*source=='+') 00091 { 00092 *destination++=' '; 00093 ++source; 00094 } 00095 else 00096 *destination++=*source++; 00097 00098 if(++i>=size) break; 00099 } 00100 return destination-start; 00101 } 00102 00103 template void Fastcgipp::Http::Environment<char>::fill(const char* data, size_t size); 00104 template void Fastcgipp::Http::Environment<wchar_t>::fill(const char* data, size_t size); 00105 template<class charT> void Fastcgipp::Http::Environment<charT>::fill(const char* data, size_t size) 00106 { 00107 using namespace std; 00108 using namespace boost; 00109 00110 while(size) 00111 {{ 00112 size_t nameSize; 00113 size_t valueSize; 00114 const char* name; 00115 const char* value; 00116 Protocol::processParamHeader(data, size, name, nameSize, value, valueSize); 00117 size-=value-data+valueSize; 00118 data=value+valueSize; 00119 00120 switch(nameSize) 00121 { 00122 case 9: 00123 if(!memcmp(name, "HTTP_HOST", 9)) 00124 charToString(value, valueSize, host); 00125 else if(!memcmp(name, "PATH_INFO", 9)) 00126 { 00127 boost::scoped_array<char> buffer(new char[valueSize]); 00128 const char* source=value; 00129 int size=-1; 00130 for(; source<value+valueSize+1; ++source, ++size) 00131 { 00132 if(*source == '/' || source == value+valueSize) 00133 { 00134 if(size > 0) 00135 { 00136 percentEscapedToRealBytes(source-size, buffer.get(), size); 00137 pathInfo.push_back(std::basic_string<charT>()); 00138 charToString(buffer.get(), size, pathInfo.back()); 00139 } 00140 size=-1; 00141 } 00142 } 00143 } 00144 break; 00145 case 11: 00146 if(!memcmp(name, "HTTP_ACCEPT", 11)) 00147 charToString(value, valueSize, acceptContentTypes); 00148 else if(!memcmp(name, "HTTP_COOKIE", 11)) 00149 decodeUrlEncoded(value, valueSize, cookies, ';'); 00150 else if(!memcmp(name, "SERVER_ADDR", 11)) 00151 serverAddress.assign(value, value+valueSize); 00152 else if(!memcmp(name, "REMOTE_ADDR", 11)) 00153 remoteAddress.assign(value, value+valueSize); 00154 else if(!memcmp(name, "SERVER_PORT", 11)) 00155 serverPort=atoi(value, value+valueSize); 00156 else if(!memcmp(name, "REMOTE_PORT", 11)) 00157 remotePort=atoi(value, value+valueSize); 00158 else if(!memcmp(name, "SCRIPT_NAME", 11)) 00159 charToString(value, valueSize, scriptName); 00160 else if(!memcmp(name, "REQUEST_URI", 11)) 00161 charToString(value, valueSize, requestUri); 00162 break; 00163 case 12: 00164 if(!memcmp(name, "HTTP_REFERER", 12) && valueSize) 00165 charToString(value, valueSize, referer); 00166 else if(!memcmp(name, "CONTENT_TYPE", 12)) 00167 { 00168 const char* end=(char*)memchr(value, ';', valueSize); 00169 charToString(value, end?end-value:valueSize, contentType); 00170 if(end) 00171 { 00172 const char* start=(char*)memchr(end, '=', valueSize-(end-data)); 00173 if(start) 00174 { 00175 boundarySize=valueSize-(++start-value); 00176 boundary.reset(new char[boundarySize]); 00177 memcpy(boundary.get(), start, boundarySize); 00178 } 00179 } 00180 } 00181 else if(!memcmp(name, "QUERY_STRING", 12) && valueSize) 00182 decodeUrlEncoded(value, valueSize, gets); 00183 break; 00184 case 13: 00185 if(!memcmp(name, "DOCUMENT_ROOT", 13)) 00186 charToString(value, valueSize, root); 00187 break; 00188 case 14: 00189 if(!memcmp(name, "REQUEST_METHOD", 14)) 00190 { 00191 requestMethod = HTTP_METHOD_ERROR; 00192 switch(valueSize) 00193 { 00194 case 3: 00195 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_GET], 3)) requestMethod = HTTP_METHOD_GET; 00196 else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_PUT], 3)) requestMethod = HTTP_METHOD_PUT; 00197 break; 00198 case 4: 00199 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_HEAD], 4)) requestMethod = HTTP_METHOD_HEAD; 00200 else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_POST], 4)) requestMethod = HTTP_METHOD_POST; 00201 break; 00202 case 5: 00203 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_TRACE], 5)) requestMethod = HTTP_METHOD_TRACE; 00204 break; 00205 case 6: 00206 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_DELETE], 6)) requestMethod = HTTP_METHOD_DELETE; 00207 break; 00208 case 7: 00209 if(!memcmp(value, requestMethodLabels[HTTP_METHOD_OPTIONS], 7)) requestMethod = HTTP_METHOD_OPTIONS; 00210 else if(!memcmp(value, requestMethodLabels[HTTP_METHOD_OPTIONS], 7)) requestMethod = HTTP_METHOD_CONNECT; 00211 break; 00212 } 00213 } 00214 else if(!memcmp(name, "CONTENT_LENGTH", 14)) 00215 contentLength=atoi(value, value+valueSize); 00216 break; 00217 case 15: 00218 if(!memcmp(name, "HTTP_USER_AGENT", 15)) 00219 charToString(value, valueSize, userAgent); 00220 else if(!memcmp(name, "HTTP_KEEP_ALIVE", 15)) 00221 keepAlive=atoi(value, value+valueSize); 00222 break; 00223 case 18: 00224 if(!memcmp(name, "HTTP_IF_NONE_MATCH", 18)) 00225 etag=atoi(value, value+valueSize); 00226 break; 00227 case 19: 00228 if(!memcmp(name, "HTTP_ACCEPT_CHARSET", 19)) 00229 charToString(value, valueSize, acceptCharsets); 00230 break; 00231 case 20: 00232 if(!memcmp(name, "HTTP_ACCEPT_LANGUAGE", 20)) 00233 charToString(value, valueSize, acceptLanguages); 00234 break; 00235 case 22: 00236 if(!memcmp(name, "HTTP_IF_MODIFIED_SINCE", 22)) 00237 { 00238 stringstream dateStream; 00239 dateStream.write(value, valueSize); 00240 dateStream.imbue(locale(locale::classic(), new posix_time::time_input_facet("%a, %d %b %Y %H:%M:%S GMT"))); 00241 dateStream >> ifModifiedSince; 00242 } 00243 break; 00244 } 00245 }} 00246 } 00247 00248 template bool Fastcgipp::Http::Environment<char>::fillPostBuffer(const char* data, size_t size); 00249 template bool Fastcgipp::Http::Environment<wchar_t>::fillPostBuffer(const char* data, size_t size); 00250 template<class charT> bool Fastcgipp::Http::Environment<charT>::fillPostBuffer(const char* data, size_t size) 00251 { 00252 if(!m_postBuffer) 00253 { 00254 m_postBuffer.reset(new char[contentLength]); 00255 pPostBuffer=m_postBuffer.get(); 00256 } 00257 00258 size_t trueSize=minPostBufferSize(size); 00259 if(trueSize) 00260 { 00261 std::memcpy(pPostBuffer, data, trueSize); 00262 pPostBuffer+=trueSize; 00263 return true; 00264 } 00265 else 00266 return false; 00267 } 00268 00269 template void Fastcgipp::Http::Environment<char>::parsePostsMultipart(); 00270 template void Fastcgipp::Http::Environment<wchar_t>::parsePostsMultipart(); 00271 template<class charT> void Fastcgipp::Http::Environment<charT>::parsePostsMultipart() 00272 { 00273 using namespace std; 00274 00275 if(!m_postBuffer) 00276 return; 00277 00278 const char cName[] = "name=\""; 00279 const char cFilename[] = "filename=\""; 00280 const char cContentType[] = "Content-Type: "; 00281 const char cBodyStart[] = "\r\n\r\n"; 00282 00283 pPostBuffer=m_postBuffer.get()+boundarySize+1; 00284 const char* contentTypeStart=0; 00285 ssize_t contentTypeSize=-1; 00286 const char* nameStart=0; 00287 ssize_t nameSize=-1; 00288 const char* filenameStart=0; 00289 ssize_t filenameSize=-1; 00290 const char* bodyStart=0; 00291 ssize_t bodySize=-1; 00292 enum ParseState { HEADER, NAME, FILENAME, CONTENT_TYPE, BODY } parseState=HEADER; 00293 for(pPostBuffer=m_postBuffer.get()+boundarySize+2; pPostBuffer<m_postBuffer.get()+contentLength; ++pPostBuffer) 00294 { 00295 switch(parseState) 00296 { 00297 case HEADER: 00298 { 00299 if(nameSize == -1) 00300 { 00301 const size_t size=minPostBufferSize(sizeof(cName)-1); 00302 if(!memcmp(pPostBuffer, cName, size)) 00303 { 00304 pPostBuffer+=size-1; 00305 nameStart=pPostBuffer+1; 00306 parseState=NAME; 00307 continue; 00308 } 00309 } 00310 if(filenameSize == -1) 00311 { 00312 const size_t size=minPostBufferSize(sizeof(cFilename)-1); 00313 if(!memcmp(pPostBuffer, cFilename, size)) 00314 { 00315 pPostBuffer+=size-1; 00316 filenameStart=pPostBuffer+1; 00317 parseState=FILENAME; 00318 continue; 00319 } 00320 } 00321 if(contentTypeSize == -1) 00322 { 00323 const size_t size=minPostBufferSize(sizeof(cContentType)-1); 00324 if(!memcmp(pPostBuffer, cContentType, size)) 00325 { 00326 pPostBuffer+=size-1; 00327 contentTypeStart=pPostBuffer+1; 00328 parseState=CONTENT_TYPE; 00329 continue; 00330 } 00331 } 00332 if(bodySize == -1) 00333 { 00334 const size_t size=minPostBufferSize(sizeof(cBodyStart)-1); 00335 if(!memcmp(pPostBuffer, cBodyStart, size)) 00336 { 00337 pPostBuffer+=size-1; 00338 bodyStart=pPostBuffer+1; 00339 parseState=BODY; 00340 continue; 00341 } 00342 } 00343 continue; 00344 } 00345 00346 case NAME: 00347 { 00348 if(*pPostBuffer == '"') 00349 { 00350 nameSize=pPostBuffer-nameStart; 00351 parseState=HEADER; 00352 } 00353 continue; 00354 } 00355 00356 case FILENAME: 00357 { 00358 if(*pPostBuffer == '"') 00359 { 00360 filenameSize=pPostBuffer-filenameStart; 00361 parseState=HEADER; 00362 } 00363 continue; 00364 } 00365 00366 case CONTENT_TYPE: 00367 { 00368 if(*pPostBuffer == '\r' || *pPostBuffer == '\n') 00369 { 00370 contentTypeSize=pPostBuffer-contentTypeStart; 00371 --pPostBuffer; 00372 parseState=HEADER; 00373 } 00374 continue; 00375 } 00376 00377 case BODY: 00378 { 00379 const size_t size=minPostBufferSize(sizeof(boundarySize)-1); 00380 if(!memcmp(pPostBuffer, boundary.get(), size)) 00381 { 00382 bodySize=pPostBuffer-bodyStart-2; 00383 if(bodySize<0) bodySize=0; 00384 else if(bodySize>=2 && *(bodyStart+bodySize-1)=='\n' && *(bodyStart+bodySize-2)=='\r') 00385 bodySize -= 2; 00386 00387 if(nameSize != -1) 00388 { 00389 basic_string<charT> name; 00390 charToString(nameStart, nameSize, name); 00391 00392 Post<charT>& thePost=posts[name]; 00393 if(contentTypeSize != -1) 00394 { 00395 thePost.type=Post<charT>::file; 00396 charToString(contentTypeStart, contentTypeSize, thePost.contentType); 00397 if(filenameSize != -1) charToString(filenameStart, filenameSize, thePost.filename); 00398 thePost.m_size=bodySize; 00399 if(bodySize) 00400 { 00401 thePost.m_data = new char[bodySize]; 00402 memcpy(thePost.m_data, bodyStart, bodySize); 00403 } 00404 } 00405 else 00406 { 00407 thePost.type=Post<charT>::form; 00408 charToString(bodyStart, bodySize, thePost.value); 00409 } 00410 } 00411 00412 pPostBuffer+=size; 00413 parseState=HEADER; 00414 contentTypeStart=0; 00415 contentTypeSize=-1; 00416 nameStart=0; 00417 nameSize=-1; 00418 filenameStart=0; 00419 filenameSize=-1; 00420 bodyStart=0; 00421 bodySize=-1; 00422 } 00423 continue; 00424 } 00425 } 00426 } 00427 } 00428 00429 template void Fastcgipp::Http::Environment<char>::parsePostsUrlEncoded(); 00430 template void Fastcgipp::Http::Environment<wchar_t>::parsePostsUrlEncoded(); 00431 template<class charT> void Fastcgipp::Http::Environment<charT>::parsePostsUrlEncoded() 00432 { 00433 if(!m_postBuffer) 00434 return; 00435 00436 char* nameStart=m_postBuffer.get(); 00437 size_t nameSize; 00438 char* valueStart=0; 00439 size_t valueSize; 00440 00441 for(char* i=m_postBuffer.get(); i<=m_postBuffer.get()+contentLength; ++i) 00442 { 00443 if(*i == '=' && nameStart && !valueStart) 00444 { 00445 nameSize=percentEscapedToRealBytes(nameStart, nameStart, i-nameStart); 00446 valueStart=i+1; 00447 } 00448 else if( (i==m_postBuffer.get()+contentLength || *i == '&') && nameStart && valueStart) 00449 { 00450 valueSize=percentEscapedToRealBytes(valueStart, valueStart, i-valueStart); 00451 00452 std::basic_string<charT> name; 00453 charToString(nameStart, nameSize, name); 00454 nameStart=i+1; 00455 Post<charT>& thePost=posts[name]; 00456 thePost.type=Post<charT>::form; 00457 charToString(valueStart, valueSize, thePost.value); 00458 valueStart=0; 00459 } 00460 } 00461 } 00462 00463 bool Fastcgipp::Http::SessionId::seeded=false; 00464 00465 Fastcgipp::Http::SessionId::SessionId() 00466 { 00467 if(!seeded) 00468 { 00469 std::srand(boost::posix_time::microsec_clock::universal_time().time_of_day().fractional_seconds()); 00470 seeded=true; 00471 } 00472 00473 for(char* i=data; i<data+size; ++i) 00474 *i=char(rand()%256); 00475 timestamp = boost::posix_time::second_clock::universal_time(); 00476 } 00477 00478 template const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=<const char>(const char* data_); 00479 template const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=<const wchar_t>(const wchar_t* data_); 00480 template<class charT> const Fastcgipp::Http::SessionId& Fastcgipp::Http::SessionId::operator=(charT* data_) 00481 { 00482 std::memset(data, 0, size); 00483 base64Decode(data_, data_+size*4/3, data); 00484 timestamp = boost::posix_time::second_clock::universal_time(); 00485 return *this; 00486 } 00487 00488 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); 00489 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); 00490 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) 00491 { 00492 using namespace std; 00493 00494 boost::scoped_array<char> buffer(new char[size]); 00495 memcpy(buffer.get(), data, size); 00496 00497 char* nameStart=buffer.get(); 00498 size_t nameSize; 00499 char* valueStart=0; 00500 size_t valueSize; 00501 for(char* i=buffer.get(); i<=buffer.get()+size; ++i) 00502 { 00503 if(i==buffer.get()+size || *i == fieldSeperator) 00504 { 00505 if(nameStart && valueStart) 00506 { 00507 valueSize=percentEscapedToRealBytes(valueStart, valueStart, i-valueStart); 00508 00509 basic_string<charT> name; 00510 charToString(nameStart, nameSize, name); 00511 nameStart=i+1; 00512 basic_string<charT>& value=output[name]; 00513 charToString(valueStart, valueSize, value); 00514 valueStart=0; 00515 } 00516 } 00517 00518 else if(*i == ' ' && nameStart && !valueStart) 00519 ++nameStart; 00520 00521 else if(*i == '=' && nameStart && !valueStart) 00522 { 00523 nameSize=percentEscapedToRealBytes(nameStart, nameStart, i-nameStart); 00524 valueStart=i+1; 00525 } 00526 } 00527 } 00528 00529 const char Fastcgipp::Http::base64Characters[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 00530 const char* Fastcgipp::Http::requestMethodLabels[]= { 00531 "ERROR", 00532 "HEAD", 00533 "GET", 00534 "POST", 00535 "PUT", 00536 "DELETE", 00537 "TRACE", 00538 "OPTIONS", 00539 "CONNECT" 00540 }; 00541 00542 template const std::basic_string<char>& Fastcgipp::Http::Environment<char>::findCookie(const char* key) const; 00543 template const std::basic_string<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findCookie(const wchar_t* key) const; 00544 template<class charT> const std::basic_string<charT>& Fastcgipp::Http::Environment<charT>::findCookie(const charT* key) const 00545 { 00546 static const std::basic_string<charT> emptyString; 00547 typename Cookies::const_iterator it=cookies.find(key); 00548 if(it==cookies.end()) 00549 return emptyString; 00550 else 00551 return it->second; 00552 } 00553 00554 template const std::basic_string<char>& Fastcgipp::Http::Environment<char>::findGet(const char* key) const; 00555 template const std::basic_string<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findGet(const wchar_t* key) const; 00556 template<class charT> const std::basic_string<charT>& Fastcgipp::Http::Environment<charT>::findGet(const charT* key) const 00557 { 00558 static const std::basic_string<charT> emptyString; 00559 typename Gets::const_iterator it=gets.find(key); 00560 if(it==gets.end()) 00561 return emptyString; 00562 else 00563 return it->second; 00564 } 00565 00566 template const Fastcgipp::Http::Post<char>& Fastcgipp::Http::Environment<char>::findPost(const char* key) const; 00567 template const Fastcgipp::Http::Post<wchar_t>& Fastcgipp::Http::Environment<wchar_t>::findPost(const wchar_t* key) const; 00568 template<class charT> const Fastcgipp::Http::Post<charT>& Fastcgipp::Http::Environment<charT>::findPost(const charT* key) const 00569 { 00570 static const Post<charT> emptyPost; 00571 typename Posts::const_iterator it=posts.find(key); 00572 if(it==posts.end()) 00573 return emptyPost; 00574 else 00575 return it->second; 00576 } 00577 00578 template bool Fastcgipp::Http::Environment<char>::checkForGet(const char* key) const; 00579 template bool Fastcgipp::Http::Environment<wchar_t>::checkForGet(const wchar_t* key) const; 00580 template<class charT> bool Fastcgipp::Http::Environment<charT>::checkForGet(const charT* key) const 00581 { 00582 typename Gets::const_iterator it=gets.find(key); 00583 if(it==gets.end()) 00584 return false; 00585 else 00586 return true; 00587 } 00588 00589 template bool Fastcgipp::Http::Environment<char>::checkForPost(const char* key) const; 00590 template bool Fastcgipp::Http::Environment<wchar_t>::checkForPost(const wchar_t* key) const; 00591 template<class charT> bool Fastcgipp::Http::Environment<charT>::checkForPost(const charT* key) const 00592 { 00593 typename Posts::const_iterator it=posts.find(key); 00594 if(it==posts.end()) 00595 return false; 00596 else 00597 return true; 00598 } 00599 00600 Fastcgipp::Http::Address& Fastcgipp::Http::Address::operator&=(const Address& x) 00601 { 00602 *(uint64_t*)m_data &= *(const uint64_t*)x.m_data; 00603 *(uint64_t*)(m_data+size/2) &= *(const uint64_t*)(x.m_data+size/2); 00604 00605 return *this; 00606 } 00607 00608 Fastcgipp::Http::Address Fastcgipp::Http::Address::operator&(const Address& x) const 00609 { 00610 Address address(*this); 00611 address &= x; 00612 00613 return address; 00614 } 00615 00616 void Fastcgipp::Http::Address::assign(const char* start, const char* end) 00617 { 00618 const char* read=start-1; 00619 unsigned char* write=m_data; 00620 unsigned char* pad=0; 00621 unsigned char offset; 00622 uint16_t chunk=0; 00623 bool error=false; 00624 00625 while(1) 00626 { 00627 ++read; 00628 if(read >= end || *read == ':') 00629 { 00630 if(read == start || *(read-1) == ':') 00631 { 00632 if(pad && pad != write) 00633 { 00634 error=true; 00635 break; 00636 } 00637 else 00638 pad = write; 00639 } 00640 else 00641 { 00642 *write = (chunk&0xff00)>>8; 00643 *(write+1) = chunk&0x00ff; 00644 chunk = 0; 00645 write += 2; 00646 if(write>=m_data+size || read >= end) 00647 break; 00648 } 00649 continue; 00650 } 00651 else if('0' <= *read && *read <= '9') 00652 offset = '0'; 00653 else if('A' <= *read && *read <= 'F') 00654 offset = 'A'-10; 00655 else if('a' <= *read && *read <= 'f') 00656 offset = 'a'-10; 00657 else if(*read == '.') 00658 { 00659 if(write == m_data) 00660 { 00661 // We must be getting a pure ipv4 formatted address. Not an ::ffff:xxx.xxx.xxx.xxx style ipv4 address. 00662 *(uint16_t*)write = 0xffff; 00663 pad = m_data; 00664 write+=2; 00665 } 00666 else if(write - m_data > 12) 00667 { 00668 // We don't have enought space for an ipv4 address 00669 error=true; 00670 break; 00671 } 00672 00673 // First convert the value stored in chunk to the first part of the ipv4 address 00674 *write = 0; 00675 for(int i=0; i<3; ++i) 00676 { 00677 *write = *write * 10 + ((chunk&0x0f00)>>8); 00678 chunk <<= 4; 00679 } 00680 ++write; 00681 00682 // Now we'll get the remaining pieces 00683 for(int i=0; i<3 && read<end; ++i) 00684 { 00685 const char* point=(const char*)memchr(read, '.', end-read); 00686 if(point && point<end-1) 00687 read=point; 00688 else 00689 { 00690 error=true; 00691 break; 00692 } 00693 *write++ = atoi(++read, end); 00694 } 00695 break; 00696 } 00697 else 00698 { 00699 error=true; 00700 break; 00701 } 00702 chunk <<= 4; 00703 chunk |= *read-offset; 00704 } 00705 00706 if(error) 00707 std::memset(m_data, 0, size); 00708 else if(pad) 00709 { 00710 if(pad==write) 00711 std::memset(write, 0, size-(write-m_data)); 00712 else 00713 { 00714 const size_t padSize=m_data+size-write; 00715 std::memmove(pad+padSize, pad, write-pad); 00716 std::memset(pad, 0, padSize); 00717 } 00718 } 00719 } 00720 00721 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); 00722 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); 00723 template<class charT, class Traits> std::basic_ostream<charT, Traits>& Fastcgipp::Http::operator<<(std::basic_ostream<charT, Traits>& os, const Address& address) 00724 { 00725 using namespace std; 00726 if(!os.good()) return os; 00727 00728 try 00729 { 00730 typename basic_ostream<charT, Traits>::sentry opfx(os); 00731 if(opfx) 00732 { 00733 streamsize fieldWidth=os.width(0); 00734 charT buffer[40]; 00735 charT* bufPtr=buffer; 00736 locale loc(os.getloc(), new num_put<charT, charT*>); 00737 00738 const uint16_t* subStart=0; 00739 const uint16_t* subEnd=0; 00740 { 00741 const uint16_t* subStartCandidate; 00742 const uint16_t* subEndCandidate; 00743 bool inZero = false; 00744 00745 for(const uint16_t* it = (const uint16_t*)address.data(); it < (const uint16_t*)(address.data()+Address::size); ++it) 00746 { 00747 if(*it == 0) 00748 { 00749 if(!inZero) 00750 { 00751 subStartCandidate = it; 00752 subEndCandidate = it; 00753 inZero=true; 00754 } 00755 ++subEndCandidate; 00756 } 00757 else if(inZero) 00758 { 00759 if(subEndCandidate-subStartCandidate > subEnd-subStart) 00760 { 00761 subStart=subStartCandidate; 00762 subEnd=subEndCandidate-1; 00763 } 00764 inZero=false; 00765 } 00766 } 00767 if(inZero) 00768 { 00769 if(subEndCandidate-subStartCandidate > subEnd-subStart) 00770 { 00771 subStart=subStartCandidate; 00772 subEnd=subEndCandidate-1; 00773 } 00774 inZero=false; 00775 } 00776 } 00777 00778 ios_base::fmtflags oldFlags = os.flags(); 00779 os.setf(ios::hex, ios::basefield); 00780 00781 if(subStart==(const uint16_t*)address.data() && subEnd==(const uint16_t*)address.data()+4 && *((const uint16_t*)address.data()+5) == 0xffff) 00782 { 00783 // It is an ipv4 address 00784 *bufPtr++=os.widen(':'); 00785 *bufPtr++=os.widen(':'); 00786 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(bufPtr, os, os.fill(), static_cast<unsigned long int>(0xffff)); 00787 *bufPtr++=os.widen(':'); 00788 os.setf(ios::dec, ios::basefield); 00789 00790 for(const unsigned char* it = address.data()+12; it < address.data()+Address::size; ++it) 00791 { 00792 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(bufPtr, os, os.fill(), static_cast<unsigned long int>(*it)); 00793 *bufPtr++=os.widen('.'); 00794 } 00795 --bufPtr; 00796 } 00797 else 00798 { 00799 // It is an ipv6 address 00800 for(const uint16_t* it = (const uint16_t*)address.data(); it < (const uint16_t*)(address.data()+Address::size); ++it) 00801 { 00802 if(subStart <= it && it <= subEnd) 00803 { 00804 if(it == subStart && it == (const uint16_t*)address.data()) 00805 *bufPtr++=os.widen(':'); 00806 if(it == subEnd) 00807 *bufPtr++=os.widen(':'); 00808 } 00809 else 00810 { 00811 bufPtr=use_facet<num_put<charT, charT*> >(loc).put(bufPtr, os, os.fill(), static_cast<unsigned long int>(Protocol::readBigEndian(*it))); 00812 00813 if(it < (const uint16_t*)(address.data()+Address::size)-1) 00814 *bufPtr++=os.widen(':'); 00815 } 00816 } 00817 } 00818 00819 os.flags(oldFlags); 00820 00821 charT* ptr=buffer; 00822 ostreambuf_iterator<charT,Traits> sink(os); 00823 if(os.flags() & ios_base::left) 00824 for(int i=max(fieldWidth, bufPtr-buffer); i>0; i--) 00825 { 00826 if(ptr!=bufPtr) *sink++=*ptr++; 00827 else *sink++=os.fill(); 00828 } 00829 else 00830 for(int i=fieldWidth-(bufPtr-buffer); ptr!=bufPtr;) 00831 { 00832 if(i>0) { *sink++=os.fill(); --i; } 00833 else *sink++=*ptr++; 00834 } 00835 00836 if(sink.failed()) os.setstate(ios_base::failbit); 00837 } 00838 } 00839 catch(bad_alloc&) 00840 { 00841 ios_base::iostate exception_mask = os.exceptions(); 00842 os.exceptions(ios_base::goodbit); 00843 os.setstate(ios_base::badbit); 00844 os.exceptions(exception_mask); 00845 if(exception_mask & ios_base::badbit) throw; 00846 } 00847 catch(...) 00848 { 00849 ios_base::iostate exception_mask = os.exceptions(); 00850 os.exceptions(ios_base::goodbit); 00851 os.setstate(ios_base::failbit); 00852 os.exceptions(exception_mask); 00853 if(exception_mask & ios_base::failbit) throw; 00854 } 00855 return os; 00856 } 00857 00858 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); 00859 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); 00860 template<class charT, class Traits> std::basic_istream<charT, Traits>& Fastcgipp::Http::operator>>(std::basic_istream<charT, Traits>& is, Address& address) 00861 { 00862 using namespace std; 00863 if(!is.good()) return is; 00864 00865 ios_base::iostate err = ios::goodbit; 00866 try 00867 { 00868 typename basic_istream<charT, Traits>::sentry ipfx(is); 00869 if(ipfx) 00870 { 00871 istreambuf_iterator<charT, Traits> read(is); 00872 unsigned char buffer[Address::size]; 00873 unsigned char* write=buffer; 00874 unsigned char* pad=0; 00875 unsigned char offset; 00876 unsigned char count=0; 00877 uint16_t chunk=0; 00878 charT lastChar=0; 00879 00880 for(;;++read) 00881 { 00882 if(++count>40) 00883 { 00884 err = ios::failbit; 00885 break; 00886 } 00887 else if('0' <= *read && *read <= '9') 00888 offset = '0'; 00889 else if('A' <= *read && *read <= 'F') 00890 offset = 'A'-10; 00891 else if('a' <= *read && *read <= 'f') 00892 offset = 'a'-10; 00893 else if(*read == '.') 00894 { 00895 if(write == buffer) 00896 { 00897 // We must be getting a pure ipv4 formatted address. Not an ::ffff:xxx.xxx.xxx.xxx style ipv4 address. 00898 *(uint16_t*)write = 0xffff; 00899 pad = buffer; 00900 write+=2; 00901 } 00902 else if(write - buffer > 12) 00903 { 00904 // We don't have enought space for an ipv4 address 00905 err = ios::failbit; 00906 break; 00907 } 00908 00909 // First convert the value stored in chunk to the first part of the ipv4 address 00910 *write = 0; 00911 for(int i=0; i<3; ++i) 00912 { 00913 *write = *write * 10 + ((chunk&0x0f00)>>8); 00914 chunk <<= 4; 00915 } 00916 ++write; 00917 00918 // Now we'll get the remaining pieces 00919 for(int i=0; i<3; ++i) 00920 { 00921 if(*read != is.widen('.')) 00922 { 00923 err = ios::failbit; 00924 break; 00925 } 00926 unsigned int value; 00927 use_facet<num_get<charT, istreambuf_iterator<charT, Traits> > >(is.getloc()).get(++read, istreambuf_iterator<charT, Traits>(), is, err, value); 00928 *write++ = value; 00929 } 00930 break; 00931 } 00932 else 00933 { 00934 if(*read == ':' && (!lastChar || lastChar == ':')) 00935 { 00936 if(pad && pad != write) 00937 { 00938 err = ios::failbit; 00939 break; 00940 } 00941 else 00942 pad = write; 00943 } 00944 else 00945 { 00946 *write = (chunk&0xff00)>>8; 00947 *(write+1) = chunk&0x00ff; 00948 chunk = 0; 00949 write += 2; 00950 if(write>=buffer+Address::size) 00951 break; 00952 if(*read!=':') 00953 { 00954 if(!pad) 00955 err = ios::failbit; 00956 break; 00957 } 00958 } 00959 lastChar=':'; 00960 continue; 00961 } 00962 chunk <<= 4; 00963 chunk |= *read-offset; 00964 lastChar=*read; 00965 00966 } 00967 00968 if(err == ios::goodbit) 00969 { 00970 if(pad) 00971 { 00972 if(pad==write) 00973 std::memset(write, 0, Address::size-(write-buffer)); 00974 else 00975 { 00976 const size_t padSize=buffer+Address::size-write; 00977 std::memmove(pad+padSize, pad, write-pad); 00978 std::memset(pad, 0, padSize); 00979 } 00980 } 00981 address=buffer; 00982 } 00983 else 00984 is.setstate(err); 00985 } 00986 } 00987 catch(bad_alloc&) 00988 { 00989 ios_base::iostate exception_mask = is.exceptions(); 00990 is.exceptions(ios_base::goodbit); 00991 is.setstate(ios_base::badbit); 00992 is.exceptions(exception_mask); 00993 if(exception_mask & ios_base::badbit) throw; 00994 } 00995 catch(...) 00996 { 00997 ios_base::iostate exception_mask = is.exceptions(); 00998 is.exceptions(ios_base::goodbit); 00999 is.setstate(ios_base::failbit); 01000 is.exceptions(exception_mask); 01001 if(exception_mask & ios_base::failbit) throw; 01002 } 01003 01004 return is; 01005 } 01006 01007 Fastcgipp::Http::Address::operator bool() const 01008 { 01009 static const unsigned char nullString[size] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 01010 if(std::memcmp(m_data, nullString, size) == 0) 01011 return false; 01012 return true; 01013 }