void ck_file::open( const ck_string& path, const ck_string& mode ) { if( _f ) CK_THROW(("Attempted to open() already open file object.")); _f = fopen( path.c_str(), mode.c_str() ); if( !_f ) CK_THROW(("Unable to open file: %s (%s)",path.c_str(),mode.c_str())); }
void ck_large_files_test::test_seek_tell() { FILE* f = fopen( ASCII_FILE.c_str(), "r" ); ck_fseeko( f, 0, SEEK_END ); int64_t pos = ck_ftello( f ); UT_ASSERT( pos == ASCII_FILE_LEN ); fclose( f ); }
bool client_response::_add_line(std::list<ck_string>& lines, const ck_string& line) { if(line.starts_with("\r\n") || line.starts_with("\n")) return true; if(line.starts_with(" ") || line.starts_with("\t")) { if(!lines.empty()) lines.back() += line; else CK_STHROW(hyperhttp_exception, ("First line of header missing needed seperator.")); } else lines.push_back(line); return false; }
void ck_large_files_test::test_pre_allocated_file() { FILE* f = fopen( PRE_ALLOCATED_FILE.c_str(), "r+b" ); ck_fallocate( f, (1024*1024) ); fclose( f ); ck_file_info info; ck_stat(PRE_ALLOCATED_FILE,&info); UT_ASSERT( info.file_size == (1024*1024) ); }
void client_response::_read_chunked_body(shared_ptr<ck_stream_io> socket) { char lineBuf[MAX_HEADER_LINE+1]; bool moreChunks = true; while(moreChunks) { memset(lineBuf, 0, MAX_HEADER_LINE+1); _read_header_line(socket, lineBuf, false); if(lineBuf[0] == '0') { _consume_footer(socket); return; } if(_embed_null(lineBuf)) { const ck_string chunkLenS = lineBuf; const uint32_t chunkLen = chunkLenS.to_uint(16); // We read our chunk into a temporary "chunk" ck_memory object, we then optionally // call our "chunk callback" function... Finally, we copy the new chunk into the // main body contents object. _chunk->clear(); if(!_receive_data(socket, _chunk->extend_data(chunkLen).get_ptr(), chunkLen)) CK_STHROW(hyperhttp_exception, ("Failed to read data from socket->")); // call callback here... if( _chunkCallback ) _chunkCallback( _chunk, *this ); // We only append a chunk to our "_bodyContents" if we are not streaming ( // because "streams" potentially have no end, so an ck_memory that contains the // complete body contents would just grow forever). if(!_streaming) memcpy(_bodyContents->extend_data(chunkLen).get_ptr(), _chunk->map().get_ptr(), chunkLen); _read_end_of_line(socket); } } }
void client_response::_process_request_lines(const list<ck_string>& requestLines) { // Now, iterate on the header lines... for(list<ck_string>::const_iterator iter = requestLines.begin(), end = requestLines.end(); iter != end; ++iter) { const size_t firstColon = iter->find(':'); if(firstColon != string::npos) { const ck_string key = iter->substr(0, firstColon); const ck_string val = firstColon + 1 < iter->size() ? iter->substr(firstColon + 1) : ""; _add_header(key.to_lower(), val.strip_eol()); } } }
bool cppkit::ck_uuid_string_valid(const ck_string& uuid) { // XXX Note: This is a fairly shitty uuid validator. It only checks for // length and that the dashes are in the right place. This could bite us, // but I doubt it... hopefully I'm right. :) if(uuid.length() != 36) return false; if(uuid[8]!='-' || uuid[13]!='-' || uuid[18]!='-' || uuid[23]!='-') return false; return true; }
vector<ck_string> client_response::get_all_matching_headers(const ck_string& header) const { vector<ck_string> matchingHeaders; auto matches = _headerParts.find(header.to_lower()); if( matches != _headerParts.end() ) { for( auto i = (*matches).second.begin(); i != (*matches).second.end(); ++i ) matchingHeaders.push_back( *i ); } return matchingHeaders; }
int ck_ssl_socket::_compare_strings(ASN1_STRING *a, int cmp_type, ck_string hostname ) { if (!a->data || !a->length) return 0; if (cmp_type > 0) { if (cmp_type != a->type) return 0; if (cmp_type == V_ASN1_IA5STRING) return _equal_wildcard(a->data, a->length, (unsigned char*)hostname.c_str(), hostname.length() ); if (a->length == (int)hostname.length() && !memcmp(a->data, (unsigned char*)hostname.c_str(), hostname.length() )) return 1; else return 0; } else { int astrlen = 0, rv = 0; unsigned char *astr = NULL; try { astrlen = ASN1_STRING_to_UTF8(&astr, a); if (astrlen < 0) return -1; rv = _equal_wildcard(astr, astrlen, (unsigned char*)hostname.c_str(), hostname.length() ); OPENSSL_free(astr); } catch(...) { if( astr ) OPENSSL_free(astr); throw; } return rv; } }
void ck_large_files_test::setup() { FILE* f = local_fopen(ASCII_FILE,LOCAL_WRITE_MODE); fwrite(ASCII_FILE.c_str(),ASCII_FILE.length(),1,f); fclose(f); f = local_fopen(UNICODE_FILE,LOCAL_WRITE_MODE); fwrite(UNICODE_FILE.get_wide_string().data(),UNICODE_FILE.get_wide_string().length(),1,f); fclose(f); f = local_fopen( PRE_ALLOCATED_FILE, "w+b" ); fwrite(UNICODE_FILE.get_wide_string().data(),UNICODE_FILE.get_wide_string().length(),1,f); fclose(f); }
void ck_large_files_test::teardown() { #ifdef IS_WINDOWS if ( !DeleteFile(UNICODE_FILE.get_wide_string().data()) ) printf("Failed to delete unicode file\n"); if ( !DeleteFile(ASCII_FILE.get_wide_string().data()) ) printf("Failed to delete ascii file\n"); if ( !DeleteFile(PRE_ALLOCATED_FILE.get_wide_string().data()) ) printf("Failed to delete pre allocated file\n"); #endif #ifdef IS_LINUX if ( remove(ASCII_FILE.c_str()) != 0) printf("Failed to delete ascii file\n"); if (remove(UNICODE_FILE.c_str()) != 0) printf("Failed to delete unicode file\n"); if (remove(PRE_ALLOCATED_FILE.c_str()) != 0) printf("Failed to delete pre allocated file\n"); #endif }
chrono::system_clock::time_point cppkit::ck_iso_8601_to_time_point( const ck_string& str ) { const size_t tDex = str.find('T'); if (tDex == string::npos) CK_THROW(("Invalid iso 8601 string: %s",str.c_str())); const size_t dotDex = str.find('.'); const size_t zDex = str.find('Z'); const size_t plusDex = str.find('+', 1); const size_t subDex = str.find('-', str.find('-', str.find('-') + 1) + 1); if (plusDex != string::npos && subDex != string::npos) CK_THROW(("Invalid iso 8601 string: %s",str.c_str())); size_t dtEnd = dotDex; if (dtEnd == string::npos || dtEnd > zDex) dtEnd = zDex; if (dtEnd == string::npos || dtEnd > plusDex) dtEnd = plusDex; if (dtEnd == string::npos || dtEnd > subDex) dtEnd = subDex; const string dateStr = str.substr(0, tDex); const string timeStr = str.substr(tDex + 1, (dtEnd - tDex) - 1); string fracSecStr; if (dotDex != string::npos) { size_t fsEnd = zDex; if (fsEnd == string::npos || fsEnd > plusDex) fsEnd = plusDex; if (fsEnd == string::npos || fsEnd > subDex) fsEnd = subDex; const size_t fsStart = dateStr.size() + 1 + timeStr.size(); const size_t fsLen = fsEnd == string::npos ? string::npos : fsEnd - fsStart; fracSecStr = str.substr(fsStart, fsLen); } const size_t zoneDex = dateStr.size() + 1 + timeStr.size() + fracSecStr.size(); const string zoneStr = zDex == str.size() ? "" : str.substr(zoneDex); tm ttm = tm(); int yyyy = 0, mm = 0, dd = 0; SSCANF(dateStr.c_str(), "%4d-%2d-%2d", &yyyy, &mm, &dd); ttm.tm_year = yyyy - 1900; ttm.tm_mon = mm - 1; // Month since January ttm.tm_mday = dd; // Day of the month [1-31] int HH = 0, MM = 0, SS = 0; SSCANF(timeStr.c_str(), "%2d:%2d:%2d", &HH, &MM, &SS); ttm.tm_hour = HH; // Hour of the day [00-23] ttm.tm_min = MM; ttm.tm_sec = SS; // We need to go from a broken down time (struct tm) to a time_t. BUT, we have to use the right function when converting // from struct tm. mktime() assumes the struct tm is in localtime. gmtime() assumes the struct tm is in UTC. If the incoming // iso 8601 string has a 'Z' then we need to use gmtime() (or _mkgmtime() on windows), else we can use mktime(). time_t theTime = 0; if (zDex == string::npos) // input is local time theTime = mktime(&ttm); else // input is UTC { #ifdef IS_WINDOWS theTime = _mkgmtime(&ttm); #else theTime = timegm(&ttm); #endif } system_clock::time_point time_point_result = std::chrono::system_clock::from_time_t(theTime); double fracSec = stod(fracSecStr); uint32_t numMillis = (uint32_t)(fracSec * 1000); time_point_result += std::chrono::milliseconds(numMillis); return time_point_result; }
void ck_ssl_socket::connect( const ck_string& host, int port ) { unique_lock<recursive_mutex> guard( _sslLok ); if( _sok.valid() ) _sok.close(); if( _ssl ) close(); _ssl = SSL_new( _ctx ); if( !_ssl ) CK_STHROW( ck_socket_exception, ("Unable to allocate SSL object.") ); ck_string ip = host; if( ck_socket_address::is_hostname( host ) ) { vector<ck_string> addresses = ck_resolve( ck_socket_address::get_address_family(host), host ); if( addresses.size() == 0 ) CK_STHROW( ck_socket_exception, ( "Unable to resolve hostname." )); ip = addresses[0]; // If someone called SetHost(), use that value instead if( !_hostName.empty() ) SSL_set_tlsext_host_name( _ssl, _hostName.c_str() ); else SSL_set_tlsext_host_name( _ssl, host.c_str() ); } _sok.connect( ip, port ); if( _hostName.empty() ) _hostName = host; #ifdef IS_WINDOWS ULONG mode = 1; ioctlsocket( _sok.get_sok_id(), FIONBIO, &mode); #else int flags = fcntl( _sok.get_sok_id(), F_GETFL, 0); fcntl( _sok.get_sok_id(), F_SETFL, flags | O_NONBLOCK ); #endif int fd = (int)_sok.get_sok_id(); SSL_set_fd(_ssl, fd); #ifndef IS_WINDOWS signal( SIGPIPE, SIG_IGN ); #endif bool verified = false; //If someone has asked to verify, then we must SSL_connect in order //to retreive the X509 cert. Otherwise we do a passive connect if( _verifyConnection ) { //Do handshake here to get X509 int error = -1; int result = 0; // XXX - used to use member called connectTimeoutMillis uint64_t waitTime = 10000; do { ERR_clear_error(); result = SSL_connect( _ssl ); error = _handle_error( result, waitTime ); } while( waitTime > 0 && error > XSSL_ERROR_NONE ); if( result == 1 && error == XSSL_ERROR_NONE ) { X509 *cert = SSL_get_peer_certificate( _ssl ); if( cert != NULL ) { if( SSL_get_verify_result( _ssl ) == X509_V_OK ) { int check = _x509_check_host(cert, _hostName); //If check is 1, the certificate matched the hostname verified = (check == 1); if( ! verified ) CK_LOG_ERROR("WARNING: Possible man-in-the-middle attack detected. The hostname specified %s does not match the hostname in the server's X509 certificate.", _hostName.c_str() ); } else { CK_LOG_ERROR("Unable to verify the ssl certificate presented by: %s", _hostName.c_str() ); } X509_free( cert ); } else CK_LOG_ERROR("Verification was requested but the server didn't return an X509 Certificate."); if( !verified ) CK_STHROW( ck_ssl_socket_auth_exception, ("Unable to verify the ssl certificate presented by: %s", _hostName.c_str())); } return; } // This call lets OpenSSL know this socket will be used as a client. It also // enable auto renegotiation when doing io. SSL_set_connect_state( _ssl ); }
ck_string client_response::get_header(const ck_string& name) const { auto values = _headerParts.find( name.to_lower() ); return (values != _headerParts.end()) ? (*values).second.front() : ""; }
#include "cppkit/os/ck_large_files.h" #include "cppkit/ck_types.h" #include <stdio.h> #include <stdlib.h> #include "ck_large_files_test.h" using namespace std; using namespace cppkit; REGISTER_TEST_FIXTURE(ck_large_files_test); static const ck_string ASCII_FILE = "LargeFileTests_ASCII_File.txt"; static const int ASCII_FILE_LEN = strlen( ASCII_FILE.c_str() ); static const ck_string UNICODE_FILE = L"Masta_カメラ_2010-12-21_1652.txt"; static const ck_string PRE_ALLOCATED_FILE = "LargeFileTests_PreAllocatedFile.txt"; static const char* LOCAL_WRITE_MODE = "w+b"; FILE* local_fopen( const ck_string& path, const ck_string& mode ) { FILE* fp = NULL; #ifdef IS_POSIX fp = fopen( path.c_str(), mode.c_str() ); if ( !fp ) CK_THROW(( "Unable to open file: %s\n", path.c_str() )); #else errno_t err; if ( err = _wfopen_s( &fp, path.get_wide_string().c_str(), mode.get_wide_string().c_str() ) != 0 ) CK_THROW(( "fopen_s returned error code: %d.\n", (int)err ));
CK_API virtual bool handles_this_presentation( const ck_string& presentation ) { return presentation.contains( "/foo/bar" ); }
void ck_dynamic_library::load( const ck_string& libraryName ) { if( false == libraryName.empty() ) { if( (_libraryName != libraryName) && _libraryInstance ) unload(); #ifdef IS_WINDOWS _libraryInstance = ::LoadLibraryW( libraryName.get_wide_string().data() ); #else _libraryInstance = dlopen( libraryName.c_str(), RTLD_NOW | RTLD_GLOBAL ); #endif if( _libraryInstance == 0 ) { #ifdef IS_WINDOWS LPVOID str = 0; DWORD_PTR args[1] = { (DWORD_PTR)_libraryName.c_str() }; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&str, 0, (va_list*)args ); // The string already comes with a carriage return. ck_string errorString = (LPTSTR)str; LocalFree( str ); CK_THROW(("Unable to load library(%s); error(%s)", libraryName.c_str(), errorString.c_str() )); #else ck_string dlError = dlerror(); if( dlError.contains( "undefined symbol: " ) ) { vector<ck_string> parts = dlError.split( "undefined symbol: " ); if( parts.size() == 2 ) { ck_string rhs = parts[1]; const size_t closeParen = rhs.find( ')' ); ck_string mangledName = rhs.substr( 0, (rhs.size()-closeParen) ); int status = 0; char* demangled = abi::__cxa_demangle( mangledName.c_str(), NULL, NULL, &status ); ck_string demangledName = demangled; free( demangled ); CK_THROW(("Unable to load library(%s); error(%s); demangled undefined symbol(%s);", libraryName.c_str(), dlError.c_str(), demangledName.c_str() )); } } else CK_THROW(("Unable to load library(%s); error(%s)", libraryName.c_str(), dlerror() )); #endif } _libraryName = libraryName; } else CK_THROW(("Library name is empty")); }