Annotation of parser3/src/main/pa_xml_io.C, revision 1.43

1.1       paf         1: /** @file
                      2:        Parser: plugins to xml library, controlling i/o; implementation
                      3: 
1.42      moko        4:        Copyright (c) 2001-2020 Art. Lebedev Studio (http://www.artlebedev.com)
1.1       paf         5:        Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
                      6: */
                      7: 
                      8: #include "pa_xml_io.h"
                      9: 
                     10: #ifdef XML
                     11: 
1.43    ! moko       12: volatile const char * IDENT_PA_XML_IO_C="$Id: pa_xml_io.C,v 1.42 2020/12/15 17:10:37 moko Exp $" IDENT_PA_XML_IO_H;
1.1       paf        13: 
                     14: #include "libxslt/extensions.h"
                     15: 
1.17      paf        16: #include "pa_threads.h"
1.1       paf        17: #include "pa_globals.h"
                     18: #include "pa_request.h"
                     19: 
1.41      moko       20: THREAD_LOCAL HashStringBool* xml_dependencies = NULL; // every TLS should be referenced elsewhere, or GC will collect it
1.17      paf        21: 
                     22: static void add_dependency(const String::Body url) { 
1.27      moko       23:        if(xml_dependencies) // do we need to monitor now?
                     24:                xml_dependencies->put(url, true);
1.17      paf        25: }
                     26: 
1.41      moko       27: HashStringBool* pa_xmlStartMonitoringDependencies() {
                     28:        return xml_dependencies=new HashStringBool; // to keep another reference on TLS
1.17      paf        29: }
                     30: 
                     31: void pa_xmlStopMonitoringDependencies() { 
1.27      moko       32:        xml_dependencies=NULL;
1.17      paf        33: }
                     34: 
                     35: HashStringBool* pa_xmlGetDependencies() {
1.27      moko       36:        HashStringBool* result=xml_dependencies;
                     37:        xml_dependencies=NULL;
                     38:        return result;
1.17      paf        39: }
                     40: 
1.8       paf        41: #ifndef DOXYGEN
1.34      moko       42: struct MemoryStream : public PA_Allocated {
1.8       paf        43:        const char* m_buf;
                     44:        size_t m_size;
                     45:        size_t m_position;
                     46: 
1.36      moko       47:        MemoryStream(const char *a_buf) : m_buf(a_buf), m_size(strlen(m_buf)), m_position(0) {}
                     48: 
1.8       paf        49:        int read(char* a_buffer, size_t a_size) {
                     50:                size_t left=m_size-m_position;
                     51:                if(!left)
                     52:                        return 0;
                     53: 
                     54:                size_t to_read=min(a_size, left);
1.14      paf        55:                memcpy(a_buffer, m_buf+m_position, to_read);
1.8       paf        56:                m_position+=to_read;
                     57:                return to_read;
                     58:        }
                     59: 
                     60: };
                     61: #endif
                     62: 
1.38      moko       63: static int xmlFileMatchMonitor(const char* /*file_spec_cstr*/) {
                     64:        return 1; // always intercept, causing xmlFileOpenMonitor to be called
                     65: }
                     66: 
                     67: /**
1.39      moko       68:  * xmlFileOpenMonitor:
                     69:  * afilename:  the URI for matching
1.38      moko       70:  *
                     71:  * http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc
                     72:  *
                     73:  * Returns an I/O context or NULL in case of error
                     74:  */
                     75: static void *xmlFileOpenMonitor(const char* afilename) {
1.18      paf        76: #ifdef PA_SAFE_MODE
                     77: //copied from libxml/catalog.c
                     78: #      define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
                     79:        // disable attempts to consult default catalog [usually, that file belongs to other user/group]
1.37      moko       80:        if(strcmp(afilename, XML_XML_DEFAULT_CATALOG)==0)
1.18      paf        81:                return 0;
                     82: #endif
                     83: 
1.15      paf        84:        Request& r=pa_thread_request();
1.38      moko       85:        if(!strncmp(afilename, "http://localhost", 16)) {
1.15      paf        86:                const char* document_root=r.request_info.document_root;
                     87:                if(!document_root)
                     88:                        document_root=".";
1.43    ! moko       89:                afilename=pa_strcat(document_root, &afilename[16]);
        !            90:        } else {
1.37      moko       91:                if(!strstr(afilename, "http://")) {
                     92:                        if(strstr(afilename, "file://")) {
                     93:                                afilename+=7 /*strlen("file://")*/;
1.26      misha      94: #ifdef WIN32
1.37      moko       95:                                if(afilename[0]=='/' && afilename[1] && afilename[2]==':' && afilename[3]=='/') {
1.26      misha      96:                                        // skip leading slash for absolute path file:///C:/path/to/file
1.37      moko       97:                                        afilename++;
1.26      misha      98:                                }
                     99: #endif
1.37      moko      100:                        } else if(afilename[0] && afilename[1]!=':' && strstr(afilename, "://")) {
1.20      misha     101:                                pa_xmlStopMonitoringDependencies();
                    102:                                return 0; // plug out [do not handle other prefixes]
                    103:                        }
1.30      moko      104:                }
1.43    ! moko      105:                afilename=pa_strdup(afilename);
        !           106:        }
1.17      paf       107: 
1.43    ! moko      108:        add_dependency(afilename);
1.15      paf       109: 
                    110:        const char *buf;
                    111:        try {
1.43    ! moko      112:                buf=file_load_text(r, *new String(afilename),
1.35      moko      113:                        true /*fail_on_read_problem*/,
                    114:                        0 /*params*/,
                    115:                        false /*don't transcode result because it must be fit with @encoding value!*/);
1.15      paf       116:        } catch(const Exception& e) {
1.17      paf       117:                if(strcmp(e.type(), "file.missing")==0)
                    118:                        return 0; // let the library try that and report an error properly
                    119: 
1.15      paf       120:                buf=e.comment();
                    121:        } catch(...) {
1.17      paf       122:                buf="xmlFileOpen_ReadIntoStream: unknown error";
1.15      paf       123:        }
1.36      moko      124:        return (void *)new MemoryStream(buf);
1.15      paf       125: }
1.9       paf       126: 
1.35      moko      127: static int xmlFileMatchMethod(const char* filename) {
                    128:        return !strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/);
1.2       paf       129: }
                    130: 
1.5       paf       131: /// parser://method/param/here -> ^MAIN:method[/params/here]
1.35      moko      132: static void *xmlFileOpenMethod (const char* afilename) {
1.15      paf       133:        const char* buf;
                    134:        try {
                    135:                Request& r=pa_thread_request();
                    136: 
                    137:                char* s=pa_strdup(afilename+9 /*strlen("parser://")*/);
                    138:                const char* method_cstr=lsplit(&s, '/');
                    139:                const String* method=new String(method_cstr);
1.40      moko      140:                String::Body param_body("/");
1.15      paf       141:                if(s)
                    142:                        param_body.append_know_length(s, strlen(s));
                    143: 
1.40      moko      144:                const String *body=r.execute_method(r.main_class, *method, new VString(*new String(param_body, String::L_TAINTED)));
                    145:                if(!body)
1.32      moko      146:                        throw Exception(0, new String(afilename), "'%s' method not found in %s class", method_cstr, MAIN_CLASS_NAME);
1.40      moko      147:                buf=body->untaint_cstr(String::L_XML);
1.15      paf       148:        } catch(const Exception& e) {
                    149:                buf=e.comment();
                    150:        } catch(...) {
                    151:                buf="xmlFileOpenLocalhost: unknown error";
1.2       paf       152:        }
1.36      moko      153:        return (void *)new MemoryStream(buf);
1.2       paf       154: }
                    155: 
1.15      paf       156: /**
                    157:  * pa_xmlFileReadMethod:
                    158:  * @context:  the I/O context
                    159:  * @buffer:  where to drop data
                    160:  * @len:  number of bytes to write
                    161:  *
                    162:  * Read @len bytes to @buffer from the I/O channel.
                    163:  *
                    164:  * Returns the number of bytes written
                    165:  */
1.35      moko      166: static int pa_xmlFileReadMethod (void* context, char* buffer, int len){
1.2       paf       167:        MemoryStream& stream=*static_cast<MemoryStream*>(context);
                    168:        return stream.read(buffer, len);
                    169: }
                    170: 
1.35      moko      171: static int pa_xmlFileCloseMethod (void* /*context*/) {
1.2       paf       172:        return 0;
                    173: }
                    174: 
1.1       paf       175: void pa_xml_io_init() {
1.17      paf       176:        // file open monitorer [for xslt cacher]
1.9       paf       177:        // safe mode checker, always fail match, but checks non-"://" there
1.35      moko      178:        xmlRegisterInputCallbacks(xmlFileMatchMonitor, xmlFileOpenMonitor, pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.17      paf       179: 
1.37      moko      180:        // parser://method/param/here -> ^MAIN:method[/params/here] - should be last to be called first
1.35      moko      181:        xmlRegisterInputCallbacks(xmlFileMatchMethod, xmlFileOpenMethod, pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.1       paf       182: }
                    183: 
                    184: #endif

E-mail: