// ============================================================================ // // = LIBRARY // ULib - c++ library // // = FILENAME // uhttp.h - HTTP utility // // = AUTHOR // Stefano Casazza // // ============================================================================ #ifndef ULIB_HTTP_H #define ULIB_HTTP_H 1 #include #include #include #include #include #include #include #include #if defined(U_ALIAS) && defined(USE_LIBPCRE) // REWRITE RULE # include #else # include #endif #define U_HTTP_REALM "Protected Area" // HTTP Access Authentication #define U_MAX_UPLOAD_PROGRESS 16 #define U_MIN_SIZE_FOR_DEFLATE 150 // NB: google advice... #define U_HTTP_URI_EQUAL(str) ((str).equal(U_HTTP_URI_TO_PARAM)) #define U_HTTP_URI_DOSMATCH(mask,len,flags) (UServices::dosMatchWithOR(U_HTTP_URI_TO_PARAM, mask, len, flags)) class UFile; class ULock; class UEventFd; class UCommand; class UPageSpeed; class USSIPlugIn; class UHttpPlugIn; class USSLSession; class UMimeMultipart; class UModProxyService; template class URDBObjectHandler; class U_EXPORT UHTTP { public: static void init(); static void dtor(); // TYPE static bool isMobile() __pure; static bool isProxyRequest(); static bool isTSARequest() __pure; static bool isSOAPRequest() __pure; static bool isGET() { U_TRACE_NO_PARAM(0, "UHTTP::isGET()") if (U_http_method_type == HTTP_GET) U_RETURN(true); U_RETURN(false); } static bool isHEAD() { U_TRACE_NO_PARAM(0, "UHTTP::isHEAD()") if (U_http_method_type == HTTP_HEAD) U_RETURN(true); U_RETURN(false); } static bool isPOST() { U_TRACE_NO_PARAM(0, "UHTTP::isPOST()") if (U_http_method_type == HTTP_POST) U_RETURN(true); U_RETURN(false); } static bool isPUT() { U_TRACE_NO_PARAM(0, "UHTTP::isPUT()") if (U_http_method_type == HTTP_PUT) U_RETURN(true); U_RETURN(false); } static bool isPATCH() { U_TRACE_NO_PARAM(0, "UHTTP::isPATCH()") if (U_http_method_type == HTTP_PATCH) U_RETURN(true); U_RETURN(false); } static bool isDELETE() { U_TRACE_NO_PARAM(0, "UHTTP::isDELETE()") if (U_http_method_type == HTTP_DELETE) U_RETURN(true); U_RETURN(false); } static bool isCOPY() { U_TRACE_NO_PARAM(0, "UHTTP::isCOPY()") if (U_http_method_type == HTTP_COPY) U_RETURN(true); U_RETURN(false); } static bool isGETorHEAD() { U_TRACE_NO_PARAM(0, "UHTTP::isGETorHEAD()") if ((U_http_method_type & (HTTP_GET | HTTP_HEAD)) != 0) U_RETURN(true); U_RETURN(false); } static bool isGETorPOST() { U_TRACE_NO_PARAM(0, "UHTTP::isGETorPOST()") if ((U_http_method_type & (HTTP_GET | HTTP_POST)) != 0) U_RETURN(true); U_RETURN(false); } static bool isGETorHEADorPOST() { U_TRACE_NO_PARAM(0, "UHTTP::isGETorHEADorPOST()") if ((U_http_method_type & (HTTP_GET | HTTP_HEAD | HTTP_POST)) != 0) U_RETURN(true); U_RETURN(false); } static bool isPOSTorPUTorPATCH() { U_TRACE_NO_PARAM(0, "UHTTP::isPOSTorPUTorPATCH()") if ((U_http_method_type & (HTTP_POST | HTTP_PUT | HTTP_PATCH)) != 0) U_RETURN(true); U_RETURN(false); } // SERVICES static UFile* file; static UString* ext; static UString* etag; static UString* suffix; static UString* request; static UString* qcontent; static UString* pathname; static UString* rpathname; static UString* upload_dir; static UString* string_HTTP_Variables; static URDB* db_not_found; static UModProxyService* service; static UVector* vmsg_error; static UVector* vservice; static char response_buffer[64]; static int mime_index, cgi_timeout; // the time-out value in seconds for output cgi process static bool enable_caching_by_proxy_servers; static uint32_t limit_request_body, request_read_timeout, range_start, range_size, response_code; static int handlerREAD(); static bool readRequest(); static bool handlerCache(); static int manageRequest(); static int processRequest(); static void initDbNotFound(); static void setStatusDescription(); static void setEndRequestProcessing(); static bool callService(const UString& path); static bool isUriRequestNeedCertificate() __pure; static bool isValidMethod(const char* ptr) __pure; static bool manageSendfile(const char* ptr, uint32_t len); static bool checkContentLength(uint32_t length, uint32_t pos); static bool scanfHeaderRequest(const char* ptr, uint32_t size); static bool scanfHeaderResponse(const char* ptr, uint32_t size); static bool readHeaderResponse(USocket* socket, UString& buffer); static bool isValidRequest( const char* ptr, uint32_t size) __pure; static bool isValidRequestExt(const char* ptr, uint32_t size) __pure; static bool readBodyResponse(USocket* socket, UString* buffer, UString& body); static void setPathName(); static void checkForPathName() { U_TRACE_NO_PARAM(0, "UHTTP::checkForPathName()") if (pathname->empty()) { setPathName(); file->setPath(*pathname); U_INTERNAL_DUMP("file = %.*S", U_FILE_TO_TRACE(*file)) } } static uint32_t getUserAgent() { U_TRACE_NO_PARAM(0, "UHTTP::getUserAgent()") uint32_t agent = (U_http_info.user_agent_len ? u_cdb_hash((unsigned char*)U_HTTP_USER_AGENT_TO_PARAM, -1) : 0); U_RETURN(agent); } static void setUploadDir(const UString& dir) { U_TRACE(0, "UHTTP::setUploadDir(%V)", dir.rep) U_INTERNAL_ASSERT_POINTER(upload_dir) *upload_dir = dir; } static void setHostname(const char* ptr, uint32_t len) { U_TRACE(0, "UHTTP::setHostname(%.*S,%u)", len, ptr, len) // The difference between HTTP_HOST and U_HTTP_VHOST is that HTTP_HOST can include the «:PORT» text, and U_HTTP_VHOST only the name U_http_host_len = U_http_host_vlen = len; U_http_info.host = ptr; U_INTERNAL_DUMP("U_http_host_len = %u U_HTTP_HOST = %.*S", U_http_host_len, U_HTTP_HOST_TO_TRACE) // hostname[:port] for (const char* endptr = ptr+len; ptr < endptr; ++ptr) { if (*ptr == ':') { U_http_host_vlen = ptr-U_http_info.host; break; } } U_INTERNAL_DUMP("U_http_host_vlen = %u U_HTTP_VHOST = %.*S", U_http_host_vlen, U_HTTP_VHOST_TO_TRACE) } static const char* getStatusDescription(uint32_t* plen = 0); static const char* getHeaderValuePtr( const char* name, uint32_t name_len, bool nocase) __pure; static const char* getHeaderValuePtr(const UString& request, const char* name, uint32_t name_len, bool nocase) __pure; static const char* getHeaderValuePtr( const UString& name, bool nocase) { return getHeaderValuePtr( U_STRING_TO_PARAM(name), nocase); } static const char* getHeaderValuePtr(const UString& request, const UString& name, bool nocase) { return getHeaderValuePtr(request, U_STRING_TO_PARAM(name), nocase); } static UString getHeaderMimeType(const char* content, uint32_t size, const char* content_type, time_t expire = 0L, bool content_length_changeable = false); // set HTTP response message enum RedirectResponseType { NO_BODY = 0x001, REFRESH = 0x002, PARAM_DEPENDENCY = 0x004, NETWORK_AUTHENTICATION_REQUIRED = 0x008 }; static void setDynamicResponse(); static void setResponse(const UString& content_type, UString* pbody); static void setRedirectResponse(int mode, const char* ptr_location, uint32_t len_location); static void setErrorResponse(const UString& content_type, int code, const char* fmt, uint32_t len); static void setResponse() { U_TRACE_NO_PARAM(0, "UHTTP::setResponse()") U_ASSERT(ext->empty()) UClientImage_Base::body->clear(); // clean body to avoid writev() in response... handlerResponse(); } // set HTTP main error message static void setNotFound() { U_TRACE_NO_PARAM(0, "UHTTP::setNotFound()") setErrorResponse(*UString::str_ctype_html, HTTP_NOT_FOUND, "Your requested URL %.*S was not found on this server", 0); } static void setBadMethod() { U_TRACE_NO_PARAM(0, "UHTTP::setBadMethod()") U_INTERNAL_ASSERT_EQUALS(U_http_info.nResponseCode, HTTP_BAD_METHOD) setErrorResponse(*UString::str_ctype_html, HTTP_BAD_METHOD, "The requested method is not allowed for the URL %.*S", 0); } static void setBadRequest() { U_TRACE_NO_PARAM(0, "UHTTP::setBadRequest()") UClientImage_Base::resetPipelineAndSetCloseConnection(); setErrorResponse(*UString::str_ctype_html, HTTP_BAD_REQUEST, "Your requested URL %.*S was a request that this server could not understand", 0); } static void setForbidden() { U_TRACE_NO_PARAM(0, "UHTTP::setForbidden()") UClientImage_Base::setRequestForbidden(); setErrorResponse(*UString::str_ctype_html, HTTP_FORBIDDEN, "You don't have permission to access %.*S on this server", 0); } static void setUnAuthorized(); static void setInternalError() { U_TRACE_NO_PARAM(0, "UHTTP::setInternalError()") setErrorResponse(*UString::str_ctype_html, HTTP_INTERNAL_ERROR, U_CONSTANT_TO_PARAM("The server encountered an internal error or misconfiguration " "and was unable to complete your request. Please contact the server " "administrator, and inform them of the time the error occurred, and " "anything you might have done that may have caused the error. More " "information about this error may be available in the server error log")); } static void setServiceUnavailable() { U_TRACE_NO_PARAM(0, "UHTTP::setServiceUnavailable()") setErrorResponse(*UString::str_ctype_html, HTTP_UNAVAILABLE, U_CONSTANT_TO_PARAM("Sorry, the service you requested is not available at this moment. " "Please contact the server administrator and inform them about this")); } #ifdef U_HTTP_STRICT_TRANSPORT_SECURITY static UString* uri_strict_transport_security_mask; static bool isUriRequestStrictTransportSecurity() __pure; #endif // URI PROTECTION (for example directory listing) static UString* htpasswd; static UString* htdigest; static bool digest_authentication; // authentication method (digest|basic) #ifdef USE_LIBSSL static UString* uri_protected_mask; static UVector* vallow_IP; static UString* uri_request_cert_mask; static bool checkUriProtected(); static bool isUriRequestProtected() __pure; #endif #ifdef U_ALIAS static UString* alias; static bool virtual_host; static UString* global_alias; static UVector* valias; static UString* maintenance_mode_page; static void setGlobalAlias(const UString& alias); #endif // manage HTTP request service: the tables must be ordered alphabetically cause of binary search... typedef struct service_info { const char* name; uint32_t len; vPF function; } service_info; #define GET_ENTRY(name) {#name,U_CONSTANT_SIZE(#name), GET_##name} #define POST_ENTRY(name) {#name,U_CONSTANT_SIZE(#name),POST_##name} static void manageRequest(service_info* GET_table, uint32_t n1, service_info* POST_table, uint32_t n2); // ----------------------------------------------------------------------- // FORM // ----------------------------------------------------------------------- // retrieve information on specific HTML form elements // (such as checkboxes, radio buttons, and text fields), or uploaded files // ----------------------------------------------------------------------- static UString* tmpdir; static UMimeMultipart* formMulti; static UVector* form_name_value; static int getFormFirstNumericValue(int _min, int _max) __pure; static uint32_t processForm(); static void getFormValue(UString& value, const char* name, uint32_t len); static void getFormValue(UString& value, uint32_t pos); static UString getFormValue( const char* name, uint32_t len, uint32_t start, uint32_t end); static void getFormValue(UString& value, const char* name, uint32_t len, uint32_t start, uint32_t pos, uint32_t end); // COOKIE static UString* set_cookie; static uint32_t sid_counter_gen; static UString* set_cookie_option; static UString* cgi_cookie_option; static bool getCookie( UString* cookie); static void addSetCookie(const UString& cookie); // ----------------------------------------------------------------------------------------------------------------------------------- // param: "[ data expire path domain secure HttpOnly ]" // ----------------------------------------------------------------------------------------------------------------------------------- // string -- key_id or data to put in cookie -- must // int -- lifetime of the cookie in HOURS -- must (0 -> valid until browser exit) // string -- path where the cookie can be used -- opt // string -- domain which can read the cookie -- opt // bool -- secure mode -- opt // bool -- only allow HTTP usage -- opt // ----------------------------------------------------------------------------------------------------------------------------------- // RET: Set-Cookie: ulib.s=data&expire&HMAC-MD5(data&expire); expires=expire(GMT); path=path; domain=domain; secure; HttpOnly // ----------------------------------------------------------------------------------------------------------------------------------- static void setCookie(const UString& param); // HTTP SESSION static uint32_t sid_counter_cur; static UDataSession* data_session; static UDataSession* data_storage; static URDBObjectHandler* db_session; static void initSession(); static void clearSession(); static void removeDataSession(); static void setSessionCookie(UString* param = 0); static bool getDataStorage(); static bool getDataSession(); static bool getDataStorage(uint32_t index, UString& value); static bool getDataSession(uint32_t index, UString& value); static void putDataStorage(); static void putDataSession(); static void putDataStorage(uint32_t index, const char* val, uint32_t sz); static void putDataSession(uint32_t index, const char* val, uint32_t sz); static bool isNewSession() { return data_session->isNewSession(); } static bool isDataSession() { return data_session->isDataSession(); } static UString getSessionCreationTime() { return data_session->getSessionCreationTime(); } static UString getSessionLastAccessedTime() { return data_session->getSessionLastAccessedTime(); } #ifdef USE_LIBSSL static USSLSession* data_session_ssl; static URDBObjectHandler* db_session_ssl; static void initSessionSSL(); static void clearSessionSSL(); #endif static UString getKeyIdDataSession() { U_TRACE_NO_PARAM(0, "UHTTP::getKeyIdDataSession()") U_INTERNAL_ASSERT_POINTER(data_session) U_RETURN_STRING(data_session->keyid); } // HTML Pagination static uint32_t num_page_end, num_page_cur, num_page_start, num_item_tot, num_item_for_page; static UString getLinkPagination(); static void addLinkPagination(UString& link, uint32_t num_page) { U_TRACE(0, "UHTTP::addLinkPagination(%V,%u)", link.rep, num_page) # ifdef U_HTML_PAGINATION_SUPPORT UString x(100U); U_INTERNAL_DUMP("num_page_cur = %u", num_page_cur) if (num_page == num_page_cur) x.snprintf("%u", num_page); else x.snprintf("%u", num_page, num_page); (void) link.append(x); link.push_back(' '); # endif } // CGI typedef struct ucgi { const char* interpreter; char environment_type; char dir[503]; } ucgi; static UCommand* pcmd; static UString* geoip; static UString* fcgi_uri_mask; static UString* scgi_uri_mask; static bool isFCGIRequest() __pure; static bool isSCGIRequest() __pure; static bool runCGI(bool set_environment); static bool getCGIEnvironment(UString& environment, int type); static bool processCGIOutput(bool cgi_sh_script, bool bheaders); static bool processCGIRequest(UCommand* cmd, UHTTP::ucgi* cgi = 0); static bool setEnvironmentForLanguageProcessing(int type, void* env, vPFpvpcpc func); #if defined(U_ALIAS) && defined(USE_LIBPCRE) // REWRITE RULE class RewriteRule { public: // Check for memory error U_MEMORY_TEST // Allocator e Deallocator U_MEMORY_ALLOCATOR U_MEMORY_DEALLOCATOR UPCRE key; UString replacement; RewriteRule(const UString& _key, const UString& _replacement) : key(_key, PCRE_FOR_REPLACE), replacement(_replacement) { U_TRACE_REGISTER_OBJECT(0, RewriteRule, "%V,%V", _key.rep, _replacement.rep) key.study(); } ~RewriteRule() { U_TRACE_UNREGISTER_OBJECT(0, RewriteRule) } #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const U_EXPORT; #endif private: #ifdef U_COMPILER_DELETE_MEMBERS RewriteRule& operator=(const RewriteRule&) = delete; #else RewriteRule& operator=(const RewriteRule&) { return *this; } #endif }; static UVector* vRewriteRule; #endif // ------------------------------------------------------------------------------------------------------------------------------------------------ // COMMON LOG FORMAT (APACHE LIKE LOG) // ------------------------------------------------------------------------------------------------------------------------------------------------ // The Common Log Format, also known as the NCSA Common log format, is a standardized text file format used by web servers // when generating server log files. Because the format is standardized, the files may be analyzed by a variety of web analysis programs. // Each line in a file stored in the Common Log Format has the following syntax: host ident authuser date request status bytes // ------------------------------------------------------------------------------------------------------------------------------------------------ // 10.10.25.2 - - [21/May/2012:16:29:41 +0200] "GET / HTTP/1.1" 200 598 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko)" // 10.10.25.2 - - [21/May/2012:16:29:41 +0200] "GET /unirel_logo.gif HTTP/1.1" 200 3414 "http://www.unirel.com/" "Mozilla/5.0 (X11; Linux x86_64)" // ------------------------------------------------------------------------------------------------------------------------------------------------ #ifndef U_LOG_DISABLE static char iov_buffer[20]; static struct iovec iov_vec[10]; # if !defined(U_CACHE_REQUEST_DISABLE) || defined(U_SERVER_CHECK_TIME_BETWEEN_REQUEST) static uint32_t request_offset, referer_offset, agent_offset; # endif static void initApacheLikeLog(); static void prepareApacheLikeLog(); static void resetApacheLikeLog() { U_TRACE_NO_PARAM(0, "UHTTP::resetApacheLikeLog()") iov_vec[6].iov_len = iov_vec[8].iov_len = 1; iov_vec[6].iov_base = iov_vec[8].iov_base = (caddr_t) "-"; } #endif // USP (ULib Servlet Page) class UServletPage : public UDynamic { public: vPFi runDynamicPage; UServletPage() { U_TRACE_REGISTER_OBJECT(0, UServletPage, "", 0) runDynamicPage = 0; } ~UServletPage() { U_TRACE_UNREGISTER_OBJECT(0, UServletPage) } #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const U_EXPORT; #endif private: #ifdef U_COMPILER_DELETE_MEMBERS UServletPage(const UServletPage&) = delete; UServletPage& operator=(const UServletPage&) = delete; #else UServletPage(const UServletPage&) : UDynamic() {} UServletPage& operator=(const UServletPage&) { return *this; } #endif }; static bool bcallInitForAllUSP; static const char* usp_page_key; static uint32_t usp_page_key_len; static UServletPage* usp_page_ptr; static bool callEndForAllUSP(UStringRep* key, void* value); static bool callInitForAllUSP(UStringRep* key, void* value); static bool callSigHUPForAllUSP(UStringRep* key, void* value); static bool callAfterForkForAllUSP(UStringRep* key, void* value); static UServletPage* getUSP(const char* key, uint32_t key_len); // CSP (C Servlet Page) typedef int (*iPFipvc)(int,const char**); class UCServletPage { public: // Check for memory error U_MEMORY_TEST // Allocator e Deallocator U_MEMORY_ALLOCATOR U_MEMORY_DEALLOCATOR int size; void* relocated; iPFipvc prog_main; UCServletPage() { U_TRACE_REGISTER_OBJECT(0, UCServletPage, "", 0) size = 0; relocated = 0; prog_main = 0; } ~UCServletPage() { U_TRACE_UNREGISTER_OBJECT(0, UCServletPage) if (relocated) UMemoryPool::_free(relocated, size, 1); } bool compile(const UString& program); // DEBUG #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const U_EXPORT; #endif private: #ifdef U_COMPILER_DELETE_MEMBERS UCServletPage(const UCServletPage&) = delete; UCServletPage& operator=(const UCServletPage&) = delete; #else UCServletPage(const UCServletPage&) {} UCServletPage& operator=(const UCServletPage&) { return *this; } #endif }; #ifdef USE_PHP // (wrapper to embed the PHP interpreter) class UPHP : public UDynamic { public: bPF initPHP; bPF runPHP; vPF endPHP; UPHP() { U_TRACE_REGISTER_OBJECT(0, UPHP, "", 0) initPHP = runPHP = 0; endPHP = 0; } ~UPHP() { U_TRACE_UNREGISTER_OBJECT(0, UPHP) } #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const U_EXPORT; #endif private: #ifdef U_COMPILER_DELETE_MEMBERS UPHP(const UPHP&) = delete; UPHP& operator=(const UPHP&) = delete; #else UPHP(const UPHP&) : UDynamic() {} UPHP& operator=(const UPHP&) { return *this; } #endif }; static UPHP* php_embed; #endif static uint32_t npathinfo; static UString* php_mount_point; #ifdef USE_RUBY // (wrapper to embed the RUBY interpreter) class URUBY : public UDynamic { public: bPF initRUBY; bPF runRUBY; vPF endRUBY; URUBY() { U_TRACE_REGISTER_OBJECT(0, URUBY, "", 0) initRUBY = runRUBY = 0; endRUBY = 0; } ~URUBY() { U_TRACE_UNREGISTER_OBJECT(0, URUBY) } #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const U_EXPORT; #endif private: #ifdef U_COMPILER_DELETE_MEMBERS URUBY(const URUBY&) = delete; URUBY& operator=(const URUBY&) = delete; #else URUBY(const URUBY&) : UDynamic() {} URUBY& operator=(const URUBY&) { return *this; } #endif }; static URUBY* ruby_embed; static bool ruby_on_rails; static UString* ruby_libdir; #endif #ifdef USE_PYTHON // (wrapper to embed the PYTHON interpreter) class UPYTHON : public UDynamic { public: bPF initPYTHON; bPF runPYTHON; vPF endPYTHON; UPYTHON() { U_TRACE_REGISTER_OBJECT(0, UPYTHON, "", 0) initPYTHON = runPYTHON = 0; endPYTHON = 0; } ~UPYTHON() { U_TRACE_UNREGISTER_OBJECT(0, UPYTHON) } #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const U_EXPORT; #endif private: #ifdef U_COMPILER_DELETE_MEMBERS UPYTHON(const UPYTHON&) = delete; UPYTHON& operator=(const UPYTHON&) = delete; #else UPYTHON(const UPYTHON&) : UDynamic() {} UPYTHON& operator=(const UPYTHON&) { return *this; } #endif }; static UPYTHON* python_embed; static UString* py_project_app; static UString* py_project_root; static UString* py_virtualenv_path; #endif #if defined(USE_PAGE_SPEED) || defined(USE_LIBV8) typedef void (*vPFstr)(UString&); #endif #ifdef USE_PAGE_SPEED // (Google Page Speed) typedef void (*vPFpcstr)(const char*, UString&); class UPageSpeed : public UDynamic { public: vPFpcstr minify_html; vPFstr optimize_gif, optimize_png, optimize_jpg; UPageSpeed() { U_TRACE_REGISTER_OBJECT(0, UPageSpeed, "", 0) minify_html = 0; optimize_gif = optimize_png = optimize_jpg = 0; } ~UPageSpeed() { U_TRACE_UNREGISTER_OBJECT(0, UPageSpeed) } #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const U_EXPORT; #endif private: #ifdef U_COMPILER_DELETE_MEMBERS UPageSpeed(const UPageSpeed&) = delete; UPageSpeed& operator=(const UPageSpeed&) = delete; #else UPageSpeed(const UPageSpeed&) : UDynamic() {} UPageSpeed& operator=(const UPageSpeed&) { return *this; } #endif }; static UPageSpeed* page_speed; #endif #ifdef USE_LIBV8 // (Google V8 JavaScript Engine) class UV8JavaScript : public UDynamic { public: vPFstr runv8; UV8JavaScript() { U_TRACE_REGISTER_OBJECT(0, UV8JavaScript, "", 0) runv8 = 0; } ~UV8JavaScript() { U_TRACE_UNREGISTER_OBJECT(0, UV8JavaScript) } #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const U_EXPORT; #endif private: #ifdef U_COMPILER_DELETE_MEMBERS UV8JavaScript(const UV8JavaScript&) = delete; UV8JavaScript& operator=(const UV8JavaScript&) = delete; #else UV8JavaScript(const UV8JavaScript&) : UDynamic() {} UV8JavaScript& operator=(const UV8JavaScript&) { return *this; } #endif }; static UV8JavaScript* v8_javascript; #endif // DOCUMENT ROOT CACHE class UFileCacheData { public: // Check for memory error U_MEMORY_TEST // Allocator e Deallocator U_MEMORY_ALLOCATOR U_MEMORY_DEALLOCATOR void* ptr; // data UVector* array; // content, header, gzip(content, header) time_t mtime; // time of last modification time_t expire; // expire time of the entry uint32_t size; // size content int wd; // if directory it is a "watch list" associated with an inotify instance... mode_t mode; // file type int mime_index; // index file mime type int fd; // file descriptor bool link; // true => ptr point to another entry UFileCacheData(); UFileCacheData(const UFileCacheData& elem); ~UFileCacheData(); // STREAM #ifdef U_STDCPP_ENABLE friend U_EXPORT istream& operator>>(istream& is, UFileCacheData& d); friend U_EXPORT ostream& operator<<(ostream& os, const UFileCacheData& d); # ifdef DEBUG const char* dump(bool reset) const U_EXPORT; # endif #endif private: #ifdef U_COMPILER_DELETE_MEMBERS UFileCacheData& operator=(const UFileCacheData&) = delete; #else UFileCacheData& operator=(const UFileCacheData&) { return *this; } #endif template friend void u_construct(const T**,bool); }; static UString* cache_file_mask; static UString* cache_avoid_mask; static UString* cache_file_store; static UString* nocache_file_mask; static UFileCacheData* file_data; static UHashMap* cache_file; static UFileCacheData* file_not_in_cache_data; static bool isDataFromCache() { U_TRACE_NO_PARAM(0, "UHTTP::isDataFromCache()") U_INTERNAL_ASSERT_POINTER(file_data) U_INTERNAL_DUMP("file_data->array = %p", file_data->array) if (file_data->array != 0) U_RETURN(true); U_RETURN(false); } static bool isDataCompressFromCache() { U_TRACE_NO_PARAM(0, "UHTTP::isDataCompressFromCache()") U_INTERNAL_ASSERT_POINTER(file_data) U_INTERNAL_ASSERT_POINTER(file_data->array) if (file_data->array->size() > 2) U_RETURN(true); U_RETURN(false); } static void checkFileForCache(); static void renewFileDataInCache(); static void checkFileInCache(const char* path, uint32_t len) { U_TRACE(0, "UHTTP::checkFileInCache(%.*S,%u)", len, path, len) file_data = cache_file->at(path, len); if (file_data) { file->st_size = file_data->size; file->st_mode = file_data->mode; file->st_mtime = file_data->mtime; U_INTERNAL_DUMP("file_data->fd = %d st_size = %I st_mtime = %ld dir() = %b", file_data->fd, file->st_size, file->st_mtime, file->dir()) } } static bool isFileInCache() { U_TRACE_NO_PARAM(0, "UHTTP::isFileInCache()") checkFileInCache(U_FILE_TO_PARAM(*file)); if (file_data) U_RETURN(true); U_RETURN(false); } static uint32_t old_path_len; static void checkFileInCache1(const char* path, uint32_t len) { U_TRACE(0, "UHTTP::checkFileInCache1(%.*S,%u)", len, path, len) U_INTERNAL_DUMP("old_path_len = %u", old_path_len) if (old_path_len != len) checkFileInCache(path, (old_path_len = len)); } static UString getDataFromCache(int idx); static UString getBodyFromCache() { return getDataFromCache(0); } static UString getHeaderFromCache() { return getDataFromCache(1); }; static UString getBodyCompressFromCache() { return getDataFromCache(2); } static UString getHeaderCompressFromCache() { return getDataFromCache(3); }; static UFileCacheData* getFileInCache(const char* path, uint32_t len) { U_TRACE(0, "UHTTP::getFileInCache(%.*S,%u)", len, path, len) UHTTP::UFileCacheData* ptr_file_data = cache_file->at(path, len); U_RETURN_POINTER(ptr_file_data, UHTTP::UFileCacheData); } private: static void handlerResponse(); static UString getHTMLDirectoryList() U_NO_EXPORT; static void setMimeIndex() { U_TRACE_NO_PARAM(0, "UHTTP::setMimeIndex()") U_INTERNAL_ASSERT_POINTER(file) U_ASSERT_EQUALS(UClientImage_Base::isRequestNotFound(), false) mime_index = U_unknow; const char* ptr = u_getsuffix(U_FILE_TO_PARAM(*file)); if (ptr) (void) u_get_mimetype(ptr+1, &mime_index); } static const char* setMimeIndex(const char* suffix_ptr) { U_TRACE(0, "UHTTP::setMimeIndex(%S)", suffix_ptr) U_INTERNAL_ASSERT_POINTER(file) mime_index = U_unknow; const char* ctype = file->getMimeType(suffix_ptr, &mime_index); file_data->mime_index = mime_index; return ctype; } #ifdef DEBUG static bool cache_file_check_memory(); static bool check_memory(UStringRep* key, void* value) U_NO_EXPORT; #endif #if defined(U_ALIAS) && defined(USE_LIBPCRE) // REWRITE RULE static void processRewriteRule() U_NO_EXPORT; #endif #if defined(HAVE_SYS_INOTIFY_H) && defined(U_HTTP_INOTIFY_SUPPORT) && !defined(U_SERVER_CAPTIVE_PORTAL) static int inotify_wd; static char* inotify_name; static uint32_t inotify_len; static UString* inotify_pathname; static UStringRep* inotify_dir; static UFileCacheData* inotify_file_data; static void in_READ(); static void initInotify(); static void setInotifyPathname() U_NO_EXPORT; static bool getInotifyPathDirectory(UStringRep* key, void* value) U_NO_EXPORT; static bool checkForInotifyDirectory(UStringRep* key, void* value) U_NO_EXPORT; #endif #ifdef U_STATIC_ONLY static void loadStaticLinkedServlet(const char* name, uint32_t len, vPFi runDynamicPage) U_NO_EXPORT; #endif static void checkPath() U_NO_EXPORT; static bool callService() U_NO_EXPORT; static bool runDynamicPage() U_NO_EXPORT; static bool readBodyRequest() U_NO_EXPORT; static bool processFileCache() U_NO_EXPORT; static bool readHeaderRequest() U_NO_EXPORT; static void processGetRequest() U_NO_EXPORT; static void manageDataForCache() U_NO_EXPORT; static bool processAuthorization() U_NO_EXPORT; static bool checkPath(uint32_t len) U_NO_EXPORT; static void checkRequestForHeader() U_NO_EXPORT; static bool checkGetRequestIfRange() U_NO_EXPORT; static bool checkGetRequestIfModified() U_NO_EXPORT; static void setCGIShellScript(UString& command) U_NO_EXPORT; static bool checkIfSourceHasChangedAndCompileUSP() U_NO_EXPORT; static void removeDataSession(const UString& token) U_NO_EXPORT; static bool checkIfUSP(UStringRep* key, void* value) U_NO_EXPORT; static bool compileUSP(const char* path, uint32_t len) U_NO_EXPORT; static bool checkIfUSPLink(UStringRep* key, void* value) U_NO_EXPORT; static int checkGetRequestForRange(const UString& data) U_NO_EXPORT; static int sortRange(const void* a, const void* b) __pure U_NO_EXPORT; static bool addHTTPVariables(UStringRep* key, void* value) U_NO_EXPORT; static bool splitCGIOutput(const char*& ptr1, const char* ptr2) U_NO_EXPORT; static void putDataInCache(const UString& fmt, UString& content) U_NO_EXPORT; static bool checkDataSession(const UString& token, time_t expire) U_NO_EXPORT; static bool readDataChunked(USocket* sk, UString* pbuffer, UString& body) U_NO_EXPORT; static void setResponseForRange(uint32_t start, uint32_t end, uint32_t header) U_NO_EXPORT; #ifdef U_COMPILER_DELETE_MEMBERS UHTTP(const UHTTP&) = delete; UHTTP& operator=(const UHTTP&) = delete; #else UHTTP(const UHTTP&) {} UHTTP& operator=(const UHTTP&) { return *this; } #endif friend class USSIPlugIn; friend class UHttpPlugIn; }; template <> inline void u_destroy(const UHTTP::UFileCacheData* elem) { U_TRACE(0, "u_destroy(%p)", elem) if (elem <= (const void*)0x0000ffff) U_ERROR("u_destroy(%p)", elem); // NB: we need this check if we are at the end of UHashMap::operator>>()... if (UHashMap::istream_loading) { ((UHTTP::UFileCacheData*)elem)->ptr = ((UHTTP::UFileCacheData*)elem)->array = 0; } delete elem; } #endif