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

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

E-mail: