--- parser3/src/main/pa_xml_io.C 2004/02/13 14:01:08 1.17 +++ parser3/src/main/pa_xml_io.C 2019/11/05 19:35:00 1.37 @@ -1,7 +1,7 @@ /** @file Parser: plugins to xml library, controlling i/o; implementation - Copyright (c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ @@ -9,7 +9,7 @@ #ifdef XML -static const char * const IDENT="$Date: 2004/02/13 14:01:08 $"; +volatile const char * IDENT_PA_XML_IO_C="$Id: pa_xml_io.C,v 1.37 2019/11/05 19:35:00 moko Exp $" IDENT_PA_XML_IO_H; #include "libxslt/extensions.h" @@ -17,58 +17,35 @@ static const char * const IDENT="$Date: #include "pa_globals.h" #include "pa_request.h" -static Hash xml_dependencies; +THREAD_LOCAL HashStringBool* xml_dependencies = NULL; static void add_dependency(const String::Body url) { - pa_thread_t thread_id=pa_get_thread_id(); - HashStringBool* urls; - { - SYNCHRONIZED; - - // try to get existing for this thread_id - urls=xml_dependencies.get(thread_id); - } - - if(urls) // do we need to monitor now? - urls->put(url, true); + if(xml_dependencies) // do we need to monitor now? + xml_dependencies->put(url, true); } void pa_xmlStartMonitoringDependencies() { - pa_thread_t thread_id=pa_get_thread_id(); - HashStringBool* urls=new HashStringBool; - { - SYNCHRONIZED; // find+fill blocked - - xml_dependencies.put(thread_id, urls); - } + xml_dependencies=new HashStringBool; } void pa_xmlStopMonitoringDependencies() { - pa_thread_t thread_id=pa_get_thread_id(); - { - SYNCHRONIZED; // find+fill blocked - - xml_dependencies.put(thread_id, 0); - } + xml_dependencies=NULL; } HashStringBool* pa_xmlGetDependencies() { - pa_thread_t thread_id=pa_get_thread_id(); - { - SYNCHRONIZED; // find+remove blocked - - HashStringBool* result=xml_dependencies.get(thread_id); - xml_dependencies.remove(thread_id); - return result; - } + HashStringBool* result=xml_dependencies; + xml_dependencies=NULL; + return result; } #ifndef DOXYGEN -struct MemoryStream { +struct MemoryStream : public PA_Allocated { const char* m_buf; size_t m_size; size_t m_position; + MemoryStream(const char *a_buf) : m_buf(a_buf), m_size(strlen(m_buf)), m_position(0) {} + int read(char* a_buffer, size_t a_size) { size_t left=m_size-m_position; if(!left) @@ -83,10 +60,17 @@ struct MemoryStream { }; #endif -static void * -xmlFileOpen_ReadIntoStream (const char* do_not_store_filename, bool adjust_path_to_root_from_document_root=false) { +static void * xmlFileOpen_ReadIntoStream (const char* afilename, bool adjust_path_to_root_from_document_root=false) { +#ifdef PA_SAFE_MODE +//copied from libxml/catalog.c +# define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog" + // disable attempts to consult default catalog [usually, that file belongs to other user/group] + if(strcmp(afilename, XML_XML_DEFAULT_CATALOG)==0) + return 0; +#endif + Request& r=pa_thread_request(); - char adjust_buf[MAX_STRING]; + char adjust_buf[MAX_STRING]; if(adjust_path_to_root_from_document_root) { const char* document_root=r.request_info.document_root; if(!document_root) @@ -94,22 +78,33 @@ xmlFileOpen_ReadIntoStream (const char* adjust_buf[0]=0; strcat(adjust_buf, document_root); - strcat(adjust_buf, &do_not_store_filename[16]); - do_not_store_filename=adjust_buf; + strcat(adjust_buf, &afilename[16]); + afilename=adjust_buf; } else - if(strstr(do_not_store_filename, "file://")) - do_not_store_filename+=7/*strlen("file://")*/; - else if(*do_not_store_filename && do_not_store_filename[1]!=':' && strstr(do_not_store_filename, "://")) { - pa_xmlStopMonitoringDependencies(); - return 0; // plug out [do not handle other prefixes] + if(!strstr(afilename, "http://")) { + if(strstr(afilename, "file://")) { + afilename+=7 /*strlen("file://")*/; +#ifdef WIN32 + if(afilename[0]=='/' && afilename[1] && afilename[2]==':' && afilename[3]=='/') { + // skip leading slash for absolute path file:///C:/path/to/file + afilename++; + } +#endif + } else if(afilename[0] && afilename[1]!=':' && strstr(afilename, "://")) { + pa_xmlStopMonitoringDependencies(); + return 0; // plug out [do not handle other prefixes] + } } - const char* can_store_filename=pa_strdup(do_not_store_filename); + const char* can_store_filename=pa_strdup(afilename); add_dependency(can_store_filename); const char *buf; try { - buf=file_read_text(r.charsets, *new String(can_store_filename)); + buf=file_load_text(r, *new String(can_store_filename), + true /*fail_on_read_problem*/, + 0 /*params*/, + false /*don't transcode result because it must be fit with @encoding value!*/); } catch(const Exception& e) { if(strcmp(e.type(), "file.missing")==0) return 0; // let the library try that and report an error properly @@ -118,22 +113,17 @@ xmlFileOpen_ReadIntoStream (const char* } catch(...) { buf="xmlFileOpen_ReadIntoStream: unknown error"; } - MemoryStream* stream=new(UseGC) MemoryStream; - stream->m_buf=buf; - stream->m_size=strlen(buf); - return (void *)stream; + return (void *)new MemoryStream(buf); } -static int -xmlFileMatchMonitor(const char* /*file_spec_cstr*/) { +static int xmlFileMatchMonitor(const char* /*file_spec_cstr*/) { return 1; // always intercept, causing xmlFileOpenMonitor to be called } -static void * -xmlFileOpenMonitor(const char* filename) { + +static void *xmlFileOpenMonitor(const char* filename) { return xmlFileOpen_ReadIntoStream(filename); // handles localfile case, else returns 0 } - /** * xmlFileMatchWithLocalhostEqDocumentRoot: * filename: the URI for matching @@ -142,11 +132,8 @@ xmlFileOpenMonitor(const char* filename) * * Returns 1 if matches, 0 otherwise */ -static int -xmlFileMatchLocalhost(const char* filename) { - if (!strncmp(filename, "http://localhost", 16)) - return(1); - return(0); +static int xmlFileMatchLocalhost(const char* filename) { + return !strncmp(filename, "http://localhost", 16); } /** @@ -157,21 +144,16 @@ xmlFileMatchLocalhost(const char* filena * * Returns an I/O context or NULL in case of error */ -static void * -xmlFileOpenLocalhost (const char* filename) { +static void *xmlFileOpenLocalhost(const char* filename) { return xmlFileOpen_ReadIntoStream(filename, true/*adjust path to root from document_root*/); } -static int -xmlFileMatchMethod(const char* filename) { - if (!strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/)) - return(1); - return(0); +static int xmlFileMatchMethod(const char* filename) { + return !strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/); } /// parser://method/param/here -> ^MAIN:method[/params/here] -static void * -xmlFileOpenMethod (const char* afilename) { +static void *xmlFileOpenMethod (const char* afilename) { const char* buf; try { Request& r=pa_thread_request(); @@ -184,27 +166,17 @@ xmlFileOpenMethod (const char* afilename param_body.append_know_length(s, strlen(s)); VString* vparam=new VString(*new String(param_body, String::L_TAINTED)); - { - Temp_lang temp_lang(r, String::L_XML); // default language: XML - Request::Execute_nonvirtual_method_result body= - r.execute_nonvirtual_method(r.main_class, *method, vparam, true); - if(body.string) { - buf=body.string->cstr(String::L_UNSPECIFIED); - } else - throw Exception(0, - new String(afilename), - "'%s' method not found in %s class", - method_cstr, MAIN_CLASS_NAME); - } + Request::Execute_nonvirtual_method_result body=r.execute_nonvirtual_method(r.main_class, *method, vparam, true); + if(body.string) { + buf=body.string->untaint_cstr(String::L_XML); + } else + throw Exception(0, new String(afilename), "'%s' method not found in %s class", method_cstr, MAIN_CLASS_NAME); } catch(const Exception& e) { buf=e.comment(); } catch(...) { buf="xmlFileOpenLocalhost: unknown error"; } - MemoryStream* stream=new(UseGC) MemoryStream; - stream->m_buf=buf; - stream->m_size=strlen(buf); - return (void *)stream; + return (void *)new MemoryStream(buf); } /** @@ -217,38 +189,25 @@ xmlFileOpenMethod (const char* afilename * * Returns the number of bytes written */ -static int -pa_xmlFileReadMethod (void * context, //< MemoryStream actually - char * buffer, int len) -{ +static int pa_xmlFileReadMethod (void* context, char* buffer, int len){ MemoryStream& stream=*static_cast(context); - return stream.read(buffer, len); } -static int -pa_xmlFileCloseMethod (void * /*context*/) { +static int pa_xmlFileCloseMethod (void* /*context*/) { return 0; } - - void pa_xml_io_init() { // file open monitorer [for xslt cacher] // safe mode checker, always fail match, but checks non-"://" there - xmlRegisterInputCallbacks( - xmlFileMatchMonitor, xmlFileOpenMonitor, - pa_xmlFileReadMethod, pa_xmlFileCloseMethod); + xmlRegisterInputCallbacks(xmlFileMatchMonitor, xmlFileOpenMonitor, pa_xmlFileReadMethod, pa_xmlFileCloseMethod); // http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc - xmlRegisterInputCallbacks( - xmlFileMatchLocalhost, xmlFileOpenLocalhost, - pa_xmlFileReadMethod, pa_xmlFileCloseMethod); - - // parser://method/param/here -> ^MAIN:method[/params/here] - xmlRegisterInputCallbacks( - xmlFileMatchMethod, xmlFileOpenMethod, - pa_xmlFileReadMethod, pa_xmlFileCloseMethod); + xmlRegisterInputCallbacks(xmlFileMatchLocalhost, xmlFileOpenLocalhost, pa_xmlFileReadMethod, pa_xmlFileCloseMethod); + + // parser://method/param/here -> ^MAIN:method[/params/here] - should be last to be called first + xmlRegisterInputCallbacks(xmlFileMatchMethod, xmlFileOpenMethod, pa_xmlFileReadMethod, pa_xmlFileCloseMethod); } #endif