|
|
| version 1.27, 2010/11/24 00:44:09 | version 1.39, 2019/11/05 20:05:58 |
|---|---|
| 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-2009 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 39 HashStringBool* pa_xmlGetDependencies() | Line 39 HashStringBool* pa_xmlGetDependencies() |
| } | } |
| #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 58 struct MemoryStream { | Line 60 struct MemoryStream { |
| }; | }; |
| #endif | #endif |
| static void * | static int xmlFileMatchMonitor(const char* /*file_spec_cstr*/) { |
| xmlFileOpen_ReadIntoStream (const char* do_not_store_filename, bool adjust_path_to_root_from_document_root=false) { | return 1; // always intercept, causing xmlFileOpenMonitor to be called |
| } | |
| /** | |
| * xmlFileOpenMonitor: | |
| * afilename: the URI for matching | |
| * | |
| * http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc | |
| * | |
| * Returns an I/O context or NULL in case of error | |
| */ | |
| static void *xmlFileOpenMonitor(const char* afilename) { | |
| #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" |
| // disable attempts to consult default catalog [usually, that file belongs to other user/group] | // disable attempts to consult default catalog [usually, that file belongs to other user/group] |
| if(strcmp(do_not_store_filename, XML_XML_DEFAULT_CATALOG)==0) | if(strcmp(afilename, XML_XML_DEFAULT_CATALOG)==0) |
| return 0; | return 0; |
| #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(!strncmp(afilename, "http://localhost", 16)) { |
| const char* document_root=r.request_info.document_root; | const char* document_root=r.request_info.document_root; |
| if(!document_root) | if(!document_root) |
| document_root="."; | document_root="."; |
| adjust_buf[0]=0; | adjust_buf[0]=0; |
| strcat(adjust_buf, document_root); | strcat(adjust_buf, document_root); |
| strcat(adjust_buf, &do_not_store_filename[16]); | strcat(adjust_buf, &afilename[16]); |
| do_not_store_filename=adjust_buf; | afilename=adjust_buf; |
| } else | } else |
| if(!strstr(do_not_store_filename, "http://")) | if(!strstr(afilename, "http://")) { |
| if(strstr(do_not_store_filename, "file://")){ | if(strstr(afilename, "file://")) { |
| do_not_store_filename+=7/*strlen("file://")*/; | afilename+=7 /*strlen("file://")*/; |
| #ifdef WIN32 | #ifdef WIN32 |
| if( | if(afilename[0]=='/' && afilename[1] && afilename[2]==':' && afilename[3]=='/') { |
| 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 | // skip leading slash for absolute path file:///C:/path/to/file |
| do_not_store_filename++; | afilename++; |
| } | } |
| #endif | #endif |
| } else if(*do_not_store_filename && do_not_store_filename[1]!=':' && strstr(do_not_store_filename, "://")) { | } else if(afilename[0] && afilename[1]!=':' && strstr(afilename, "://")) { |
| pa_xmlStopMonitoringDependencies(); | pa_xmlStopMonitoringDependencies(); |
| return 0; // plug out [do not handle other prefixes] | 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); | add_dependency(can_store_filename); |
| const char *buf; | const char *buf; |
| try { | try { |
| buf=file_load_text(r, *new String(can_store_filename), | buf=file_load_text(r, *new String(can_store_filename), |
| true/*fail_on_read_problem*/, | true /*fail_on_read_problem*/, |
| 0/*params*/, | 0 /*params*/, |
| false/*don't transcode result because it must be fit with @encoding value!*/); | 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 116 xmlFileOpen_ReadIntoStream (const char* | Line 125 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 xmlFileMatchMethod(const char* filename) { |
| xmlFileMatchMonitor(const char* /*file_spec_cstr*/) { | return !strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/); |
| return 1; // always intercept, causing xmlFileOpenMonitor to be called | |
| } | |
| static void * | |
| xmlFileOpenMonitor(const char* filename) { | |
| return xmlFileOpen_ReadIntoStream(filename); // handles localfile case, else returns 0 | |
| } | |
| /** | |
| * xmlFileMatchWithLocalhostEqDocumentRoot: | |
| * filename: the URI for matching | |
| * | |
| * check if the URI matches an HTTP one | |
| * | |
| * Returns 1 if matches, 0 otherwise | |
| */ | |
| static int | |
| xmlFileMatchLocalhost(const char* filename) { | |
| if (!strncmp(filename, "http://localhost", 16)) | |
| return(1); | |
| return(0); | |
| } | |
| /** | |
| * xmlFileOpenLocalhost: | |
| * filename: the URI for matching | |
| * | |
| * http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc | |
| * | |
| * Returns an I/O context or NULL in case of error | |
| */ | |
| 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); | |
| } | } |
| /// 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 182 xmlFileOpenMethod (const char* afilename | Line 146 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->untaint_cstr(r.flang); | |
| } 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 215 xmlFileOpenMethod (const char* afilename | Line 169 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); | // parser://method/param/here -> ^MAIN:method[/params/here] - should be last to be called first |
| xmlRegisterInputCallbacks(xmlFileMatchMethod, xmlFileOpenMethod, 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); | |
| } | } |
| #endif | #endif |