|
|
| version 1.18.10.1, 2005/08/05 13:03:03 | version 1.36, 2019/11/05 19:25:51 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: plugins to xml library, controlling i/o; implementation | Parser: plugins to xml library, controlling i/o; implementation |
| Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| */ | */ |
| Line 9 | Line 9 |
| #ifdef XML | #ifdef XML |
| static const char * const IDENT="$Date$"; | volatile const char * IDENT_PA_XML_IO_C="$Id$" IDENT_PA_XML_IO_H; |
| #include "libxslt/extensions.h" | #include "libxslt/extensions.h" |
| Line 17 static const char * const IDENT="$Date$" | Line 17 static const char * const IDENT="$Date$" |
| #include "pa_globals.h" | #include "pa_globals.h" |
| #include "pa_request.h" | #include "pa_request.h" |
| static Hash<pa_thread_t, HashStringBool*> xml_dependencies; | THREAD_LOCAL HashStringBool* xml_dependencies = NULL; |
| static void add_dependency(const String::Body url) { | static void add_dependency(const String::Body url) { |
| pa_thread_t thread_id=pa_get_thread_id(); | if(xml_dependencies) // do we need to monitor now? |
| HashStringBool* urls; | xml_dependencies->put(url, true); |
| { | |
| 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); | |
| } | } |
| void pa_xmlStartMonitoringDependencies() { | void pa_xmlStartMonitoringDependencies() { |
| pa_thread_t thread_id=pa_get_thread_id(); | xml_dependencies=new HashStringBool; |
| HashStringBool* urls=new HashStringBool; | |
| { | |
| SYNCHRONIZED; // find+fill blocked | |
| xml_dependencies.put(thread_id, urls); | |
| } | |
| } | } |
| void pa_xmlStopMonitoringDependencies() { | void pa_xmlStopMonitoringDependencies() { |
| pa_thread_t thread_id=pa_get_thread_id(); | xml_dependencies=NULL; |
| { | |
| SYNCHRONIZED; // find+fill blocked | |
| xml_dependencies.put(thread_id, 0); | |
| } | |
| } | } |
| HashStringBool* pa_xmlGetDependencies() { | HashStringBool* pa_xmlGetDependencies() { |
| pa_thread_t thread_id=pa_get_thread_id(); | HashStringBool* result=xml_dependencies; |
| { | xml_dependencies=NULL; |
| SYNCHRONIZED; // find+remove blocked | return result; |
| HashStringBool* result=xml_dependencies.get(thread_id); | |
| xml_dependencies.remove(thread_id); | |
| return result; | |
| } | |
| } | } |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| struct MemoryStream { | struct MemoryStream : public PA_Allocated { |
| const char* m_buf; | const char* m_buf; |
| size_t m_size; | size_t m_size; |
| size_t m_position; | 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) { | int read(char* a_buffer, size_t a_size) { |
| size_t left=m_size-m_position; | size_t left=m_size-m_position; |
| if(!left) | if(!left) |
| Line 83 struct MemoryStream { | Line 60 struct MemoryStream { |
| }; | }; |
| #endif | #endif |
| static void * | static void * xmlFileOpen_ReadIntoStream (const char* do_not_store_filename, bool adjust_path_to_root_from_document_root=false) { |
| xmlFileOpen_ReadIntoStream (const char* do_not_store_filename, bool adjust_path_to_root_from_document_root=false) { | |
| #ifdef PA_SAFE_MODE | #ifdef PA_SAFE_MODE |
| //copied from libxml/catalog.c | //copied from libxml/catalog.c |
| # define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog" | # define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog" |
| Line 94 xmlFileOpen_ReadIntoStream (const char* | Line 70 xmlFileOpen_ReadIntoStream (const char* |
| #endif | #endif |
| Request& r=pa_thread_request(); | Request& r=pa_thread_request(); |
| char adjust_buf[MAX_STRING]; | char adjust_buf[MAX_STRING]; |
| if(adjust_path_to_root_from_document_root) { | if(adjust_path_to_root_from_document_root) { |
| const char* document_root=r.request_info.document_root; | const char* document_root=r.request_info.document_root; |
| if(!document_root) | if(!document_root) |
| Line 105 xmlFileOpen_ReadIntoStream (const char* | Line 81 xmlFileOpen_ReadIntoStream (const char* |
| strcat(adjust_buf, &do_not_store_filename[16]); | strcat(adjust_buf, &do_not_store_filename[16]); |
| do_not_store_filename=adjust_buf; | do_not_store_filename=adjust_buf; |
| } else | } else |
| if(strstr(do_not_store_filename, "file://")) | if(!strstr(do_not_store_filename, "http://")) { |
| do_not_store_filename+=7/*strlen("file://")*/; | if(strstr(do_not_store_filename, "file://")) { |
| else if(*do_not_store_filename && do_not_store_filename[1]!=':' && strstr(do_not_store_filename, "://")) { | do_not_store_filename+=7 /*strlen("file://")*/; |
| pa_xmlStopMonitoringDependencies(); | #ifdef WIN32 |
| return 0; // plug out [do not handle other prefixes] | if( |
| do_not_store_filename[0]=='/' | |
| && do_not_store_filename[1] | |
| && do_not_store_filename[2]==':' | |
| && do_not_store_filename[3]=='/' | |
| ) { | |
| // skip leading slash for absolute path file:///C:/path/to/file | |
| do_not_store_filename++; | |
| } | |
| #endif | |
| } 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] | |
| } | |
| } | } |
| const char* can_store_filename=pa_strdup(do_not_store_filename); | const char* can_store_filename=pa_strdup(do_not_store_filename); |
| Line 117 xmlFileOpen_ReadIntoStream (const char* | Line 106 xmlFileOpen_ReadIntoStream (const char* |
| const char *buf; | const char *buf; |
| try { | 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) { | } catch(const Exception& e) { |
| if(strcmp(e.type(), "file.missing")==0) | if(strcmp(e.type(), "file.missing")==0) |
| return 0; // let the library try that and report an error properly | return 0; // let the library try that and report an error properly |
| Line 126 xmlFileOpen_ReadIntoStream (const char* | Line 118 xmlFileOpen_ReadIntoStream (const char* |
| } catch(...) { | } catch(...) { |
| buf="xmlFileOpen_ReadIntoStream: unknown error"; | buf="xmlFileOpen_ReadIntoStream: unknown error"; |
| } | } |
| MemoryStream* stream=new(UseGC) MemoryStream; | return (void *)new MemoryStream(buf); |
| stream->m_buf=buf; | |
| stream->m_size=strlen(buf); | |
| return (void *)stream; | |
| } | } |
| static int | static int xmlFileMatchMonitor(const char* /*file_spec_cstr*/) { |
| xmlFileMatchMonitor(const char* /*file_spec_cstr*/) { | |
| return 1; // always intercept, causing xmlFileOpenMonitor to be called | 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 | return xmlFileOpen_ReadIntoStream(filename); // handles localfile case, else returns 0 |
| } | } |
| /** | /** |
| * xmlFileMatchWithLocalhostEqDocumentRoot: | * xmlFileMatchWithLocalhostEqDocumentRoot: |
| * filename: the URI for matching | * filename: the URI for matching |
| Line 150 xmlFileOpenMonitor(const char* filename) | Line 137 xmlFileOpenMonitor(const char* filename) |
| * | * |
| * Returns 1 if matches, 0 otherwise | * Returns 1 if matches, 0 otherwise |
| */ | */ |
| static int | static int xmlFileMatchLocalhost(const char* filename) { |
| xmlFileMatchLocalhost(const char* filename) { | return !strncmp(filename, "http://localhost", 16); |
| if (!strncmp(filename, "http://localhost", 16)) | |
| return(1); | |
| return(0); | |
| } | } |
| /** | /** |
| Line 165 xmlFileMatchLocalhost(const char* filena | Line 149 xmlFileMatchLocalhost(const char* filena |
| * | * |
| * Returns an I/O context or NULL in case of error | * Returns an I/O context or NULL in case of error |
| */ | */ |
| static void * | static void *xmlFileOpenLocalhost(const char* filename) { |
| xmlFileOpenLocalhost (const char* filename) { | |
| return xmlFileOpen_ReadIntoStream(filename, true/*adjust path to root from document_root*/); | return xmlFileOpen_ReadIntoStream(filename, true/*adjust path to root from document_root*/); |
| } | } |
| static int | static int xmlFileMatchMethod(const char* filename) { |
| xmlFileMatchMethod(const char* filename) { | return !strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/); |
| if (!strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/)) | |
| return(1); | |
| return(0); | |
| } | } |
| /// parser://method/param/here -> ^MAIN:method[/params/here] | /// parser://method/param/here -> ^MAIN:method[/params/here] |
| static void * | static void *xmlFileOpenMethod (const char* afilename) { |
| xmlFileOpenMethod (const char* afilename) { | |
| const char* buf; | const char* buf; |
| try { | try { |
| Request& r=pa_thread_request(); | Request& r=pa_thread_request(); |
| Line 192 xmlFileOpenMethod (const char* afilename | Line 171 xmlFileOpenMethod (const char* afilename |
| param_body.append_know_length(s, strlen(s)); | param_body.append_know_length(s, strlen(s)); |
| VString* vparam=new VString(*new String(param_body, String::L_TAINTED)); | VString* vparam=new VString(*new String(param_body, String::L_TAINTED)); |
| { | Request::Execute_nonvirtual_method_result body=r.execute_nonvirtual_method(r.main_class, *method, vparam, true); |
| Temp_lang temp_lang(r, String::L_XML); // default language: XML | if(body.string) { |
| Request::Execute_nonvirtual_method_result body= | buf=body.string->untaint_cstr(String::L_XML); |
| r.execute_nonvirtual_method(r.main_class, *method, vparam, true); | } else |
| if(body.string) { | throw Exception(0, new String(afilename), "'%s' method not found in %s class", method_cstr, MAIN_CLASS_NAME); |
| 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); | |
| } | |
| } catch(const Exception& e) { | } catch(const Exception& e) { |
| buf=e.comment(); | buf=e.comment(); |
| } catch(...) { | } catch(...) { |
| buf="xmlFileOpenLocalhost: unknown error"; | buf="xmlFileOpenLocalhost: unknown error"; |
| } | } |
| MemoryStream* stream=new(UseGC) MemoryStream; | return (void *)new MemoryStream(buf); |
| stream->m_buf=buf; | |
| stream->m_size=strlen(buf); | |
| return (void *)stream; | |
| } | } |
| /** | /** |
| Line 225 xmlFileOpenMethod (const char* afilename | Line 194 xmlFileOpenMethod (const char* afilename |
| * | * |
| * Returns the number of bytes written | * Returns the number of bytes written |
| */ | */ |
| static int | static int pa_xmlFileReadMethod (void* context, char* buffer, int len){ |
| pa_xmlFileReadMethod (void * context, //< MemoryStream actually | |
| char * buffer, int len) | |
| { | |
| MemoryStream& stream=*static_cast<MemoryStream*>(context); | MemoryStream& stream=*static_cast<MemoryStream*>(context); |
| return stream.read(buffer, len); | return stream.read(buffer, len); |
| } | } |
| static int | static int pa_xmlFileCloseMethod (void* /*context*/) { |
| pa_xmlFileCloseMethod (void * /*context*/) { | |
| return 0; | return 0; |
| } | } |
| void pa_xml_io_init() { | void pa_xml_io_init() { |
| // file open monitorer [for xslt cacher] | // file open monitorer [for xslt cacher] |
| // safe mode checker, always fail match, but checks non-"://" there | // safe mode checker, always fail match, but checks non-"://" there |
| xmlRegisterInputCallbacks( | xmlRegisterInputCallbacks(xmlFileMatchMonitor, xmlFileOpenMonitor, pa_xmlFileReadMethod, pa_xmlFileCloseMethod); |
| xmlFileMatchMonitor, xmlFileOpenMonitor, | |
| pa_xmlFileReadMethod, pa_xmlFileCloseMethod); | |
| // http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc | // http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc |
| xmlRegisterInputCallbacks( | xmlRegisterInputCallbacks(xmlFileMatchLocalhost, xmlFileOpenLocalhost, pa_xmlFileReadMethod, pa_xmlFileCloseMethod); |
| xmlFileMatchLocalhost, xmlFileOpenLocalhost, | |
| pa_xmlFileReadMethod, pa_xmlFileCloseMethod); | |
| // parser://method/param/here -> ^MAIN:method[/params/here] | // parser://method/param/here -> ^MAIN:method[/params/here] |
| xmlRegisterInputCallbacks( | xmlRegisterInputCallbacks(xmlFileMatchMethod, xmlFileOpenMethod, pa_xmlFileReadMethod, pa_xmlFileCloseMethod); |
| xmlFileMatchMethod, xmlFileOpenMethod, | |
| pa_xmlFileReadMethod, pa_xmlFileCloseMethod); | |
| } | } |
| #endif | #endif |