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

1.1       paf         1: /** @file
                      2:        Parser: plugins to xml library, controlling i/o; implementation
                      3: 
1.24      misha       4:        Copyright (c) 2001-2009 ArtLebedev Group (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.27    ! moko       12: static const char * const IDENT="$Date: 2009-09-25 12:58:39 $";
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.27    ! moko       20: THREAD_LOCAL HashStringBool* xml_dependencies = NULL;
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: 
                     27: void pa_xmlStartMonitoringDependencies() { 
1.27    ! moko       28:        xml_dependencies=new HashStringBool;
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
                     42: struct MemoryStream {
                     43:        const char* m_buf;
                     44:        size_t m_size;
                     45:        size_t m_position;
                     46: 
                     47:        int read(char* a_buffer, size_t a_size) {
                     48:                size_t left=m_size-m_position;
                     49:                if(!left)
                     50:                        return 0;
                     51: 
                     52:                size_t to_read=min(a_size, left);
1.14      paf        53:                memcpy(a_buffer, m_buf+m_position, to_read);
1.8       paf        54:                m_position+=to_read;
                     55:                return to_read;
                     56:        }
                     57: 
                     58: };
                     59: #endif
                     60: 
1.15      paf        61: static void *
1.17      paf        62: xmlFileOpen_ReadIntoStream (const char* do_not_store_filename, bool adjust_path_to_root_from_document_root=false) {
1.18      paf        63: #ifdef PA_SAFE_MODE
                     64: //copied from libxml/catalog.c
                     65: #      define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
                     66:        // disable attempts to consult default catalog [usually, that file belongs to other user/group]
                     67:        if(strcmp(do_not_store_filename, XML_XML_DEFAULT_CATALOG)==0)
                     68:                return 0;
                     69: #endif
                     70: 
1.15      paf        71:        Request& r=pa_thread_request();
                     72:        char adjust_buf[MAX_STRING];    
                     73:        if(adjust_path_to_root_from_document_root) {
                     74:                const char* document_root=r.request_info.document_root;
                     75:                if(!document_root)
                     76:                        document_root=".";
                     77: 
                     78:                adjust_buf[0]=0;
                     79:                strcat(adjust_buf, document_root);
1.17      paf        80:                strcat(adjust_buf, &do_not_store_filename[16]);
                     81:                do_not_store_filename=adjust_buf;
1.15      paf        82:        } else
1.20      misha      83:                if(!strstr(do_not_store_filename, "http://"))
1.26      misha      84:                        if(strstr(do_not_store_filename, "file://")){
                     85:                                do_not_store_filename+=7/*strlen("file://")*/;
                     86: #ifdef WIN32
                     87:                                if(
                     88:                                        do_not_store_filename[0]=='/'
                     89:                                        && do_not_store_filename[1]
                     90:                                        && do_not_store_filename[2]==':'
                     91:                                        && do_not_store_filename[3]=='/'
                     92:                                ){
                     93:                                        // skip leading slash for absolute path file:///C:/path/to/file
                     94:                                        do_not_store_filename++;
                     95:                                }
                     96: #endif
                     97:                        } else if(*do_not_store_filename && do_not_store_filename[1]!=':' && strstr(do_not_store_filename, "://"))  {
1.20      misha      98:                                pa_xmlStopMonitoringDependencies();
                     99:                                return 0; // plug out [do not handle other prefixes]
                    100:                        }
1.17      paf       101: 
                    102:        const char* can_store_filename=pa_strdup(do_not_store_filename);
                    103:        add_dependency(can_store_filename);
1.15      paf       104: 
                    105:        const char *buf;
                    106:        try {
1.23      misha     107:                buf=file_load_text(r, *new String(can_store_filename), 
1.22      misha     108:                                                        true/*fail_on_read_problem*/,
                    109:                                                        0/*params*/,
                    110:                                                        false/*don't transcode result because it must be fit with @encoding value!*/);
1.15      paf       111:        } catch(const Exception& e) {
1.17      paf       112:                if(strcmp(e.type(), "file.missing")==0)
                    113:                        return 0; // let the library try that and report an error properly
                    114: 
1.15      paf       115:                buf=e.comment();
                    116:        } catch(...) {
1.17      paf       117:                buf="xmlFileOpen_ReadIntoStream: unknown error";
1.15      paf       118:        }
                    119:        MemoryStream* stream=new(UseGC) MemoryStream;
                    120:        stream->m_buf=buf;
                    121:        stream->m_size=strlen(buf);
                    122:        return (void *)stream;
                    123: }
1.9       paf       124: 
                    125: static int
1.17      paf       126: xmlFileMatchMonitor(const char* /*file_spec_cstr*/) {
                    127:        return 1; // always intercept, causing xmlFileOpenMonitor to be called
1.15      paf       128: }
                    129: static void *
1.17      paf       130: xmlFileOpenMonitor(const char* filename) {
1.15      paf       131:        return xmlFileOpen_ReadIntoStream(filename); // handles localfile case, else returns 0
1.9       paf       132: }
                    133: 
                    134: 
1.1       paf       135: /**
                    136:  * xmlFileMatchWithLocalhostEqDocumentRoot:
                    137:  * filename:  the URI for matching
                    138:  *
                    139:  * check if the URI matches an HTTP one
                    140:  *
                    141:  * Returns 1 if matches, 0 otherwise
                    142:  */
                    143: static int
                    144: xmlFileMatchLocalhost(const char* filename) {
                    145:        if (!strncmp(filename, "http://localhost", 16))
                    146:                return(1);
                    147:        return(0);
                    148: }
                    149: 
                    150: /**
1.15      paf       151:  * xmlFileOpenLocalhost:
1.1       paf       152:  * filename:  the URI for matching
                    153:  *
                    154:  * http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc
                    155:  *
                    156:  * Returns an I/O context or NULL in case of error
                    157:  */
                    158: static void *
                    159: xmlFileOpenLocalhost (const char* filename) {
1.15      paf       160:        return xmlFileOpen_ReadIntoStream(filename, true/*adjust path to root from document_root*/);
1.1       paf       161: }
                    162: 
1.2       paf       163: static int
                    164: xmlFileMatchMethod(const char* filename) {
1.3       paf       165:        if (!strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/))
1.2       paf       166:                return(1);
                    167:        return(0);
                    168: }
                    169: 
1.5       paf       170: /// parser://method/param/here -> ^MAIN:method[/params/here]
1.2       paf       171: static void *
                    172: xmlFileOpenMethod (const char* afilename) {
1.15      paf       173:        const char* buf;
                    174:        try {
                    175:                Request& r=pa_thread_request();
                    176: 
                    177:                char* s=pa_strdup(afilename+9 /*strlen("parser://")*/);
                    178:                const char* method_cstr=lsplit(&s, '/');
                    179:                const String* method=new String(method_cstr);
                    180:                String::Body param_body("/");  
                    181:                if(s)
                    182:                        param_body.append_know_length(s, strlen(s));
                    183: 
                    184:                VString* vparam=new VString(*new String(param_body, String::L_TAINTED));
                    185:                {
                    186:                        Temp_lang temp_lang(r, String::L_XML); // default language: XML
                    187:                        Request::Execute_nonvirtual_method_result body=
                    188:                                r.execute_nonvirtual_method(r.main_class, *method, vparam, true);
                    189:                        if(body.string) {
1.25      misha     190:                                buf=body.string->untaint_cstr(r.flang);
1.15      paf       191:                        } else
                    192:                                throw Exception(0,
                    193:                                        new String(afilename),
                    194:                                        "'%s' method not found in %s class", 
                    195:                                                        method_cstr, MAIN_CLASS_NAME);
1.2       paf       196:                }
1.15      paf       197:        } catch(const Exception& e) {
                    198:                buf=e.comment();
                    199:        } catch(...) {
                    200:                buf="xmlFileOpenLocalhost: unknown error";
1.2       paf       201:        }
1.15      paf       202:        MemoryStream* stream=new(UseGC) MemoryStream;
                    203:        stream->m_buf=buf;
                    204:        stream->m_size=strlen(buf);
                    205:        return (void *)stream;
1.2       paf       206: }
                    207: 
1.15      paf       208: /**
                    209:  * pa_xmlFileReadMethod:
                    210:  * @context:  the I/O context
                    211:  * @buffer:  where to drop data
                    212:  * @len:  number of bytes to write
                    213:  *
                    214:  * Read @len bytes to @buffer from the I/O channel.
                    215:  *
                    216:  * Returns the number of bytes written
                    217:  */
1.2       paf       218: static int
                    219: pa_xmlFileReadMethod (void * context, //< MemoryStream actually
                    220:                                          char * buffer, int len) 
                    221: {
                    222:        MemoryStream& stream=*static_cast<MemoryStream*>(context);
                    223: 
                    224:        return stream.read(buffer, len);
                    225: }
                    226: 
                    227: static int
                    228: pa_xmlFileCloseMethod (void * /*context*/) {
                    229:        return 0;
                    230: }
                    231: 
                    232: 
1.1       paf       233: 
                    234: void pa_xml_io_init() {
1.17      paf       235:        // file open monitorer [for xslt cacher]
1.9       paf       236:        // safe mode checker, always fail match, but checks non-"://" there
                    237:        xmlRegisterInputCallbacks(
1.17      paf       238:                xmlFileMatchMonitor, xmlFileOpenMonitor,
1.15      paf       239:                pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.17      paf       240: 
1.1       paf       241:        // http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc
                    242:        xmlRegisterInputCallbacks(
                    243:                xmlFileMatchLocalhost, xmlFileOpenLocalhost,
1.8       paf       244:                pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.2       paf       245: 
1.5       paf       246:        // parser://method/param/here -> ^MAIN:method[/params/here]
1.2       paf       247:        xmlRegisterInputCallbacks(
                    248:                xmlFileMatchMethod, xmlFileOpenMethod,
                    249:                pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.1       paf       250: }
                    251: 
                    252: #endif

E-mail: