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

1.1       paf         1: /** @file
                      2:        Parser: plugins to xml library, controlling i/o; implementation
                      3: 
1.19      paf         4:        Copyright (c) 2001-2005 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.20    ! misha      12: static const char * const IDENT="$Date: 2005/08/09 08:14:53 $";
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://"))
        !           109:                        if(strstr(do_not_store_filename, "file://"))
        !           110:                                do_not_store_filename+=7/*strlen("file://")*/; 
        !           111:                        else if(*do_not_store_filename && do_not_store_filename[1]!=':' && strstr(do_not_store_filename, "://"))  {
        !           112:                                pa_xmlStopMonitoringDependencies();
        !           113:                                return 0; // plug out [do not handle other prefixes]
        !           114:                        }
1.17      paf       115: 
                    116:        const char* can_store_filename=pa_strdup(do_not_store_filename);
                    117:        add_dependency(can_store_filename);
1.15      paf       118: 
                    119:        const char *buf;
                    120:        try {
1.17      paf       121:                buf=file_read_text(r.charsets, *new String(can_store_filename));
1.15      paf       122:        } catch(const Exception& e) {
1.17      paf       123:                if(strcmp(e.type(), "file.missing")==0)
                    124:                        return 0; // let the library try that and report an error properly
                    125: 
1.15      paf       126:                buf=e.comment();
                    127:        } catch(...) {
1.17      paf       128:                buf="xmlFileOpen_ReadIntoStream: unknown error";
1.15      paf       129:        }
                    130:        MemoryStream* stream=new(UseGC) MemoryStream;
                    131:        stream->m_buf=buf;
                    132:        stream->m_size=strlen(buf);
                    133:        return (void *)stream;
                    134: }
1.9       paf       135: 
                    136: static int
1.17      paf       137: xmlFileMatchMonitor(const char* /*file_spec_cstr*/) {
                    138:        return 1; // always intercept, causing xmlFileOpenMonitor to be called
1.15      paf       139: }
                    140: static void *
1.17      paf       141: xmlFileOpenMonitor(const char* filename) {
1.15      paf       142:        return xmlFileOpen_ReadIntoStream(filename); // handles localfile case, else returns 0
1.9       paf       143: }
                    144: 
                    145: 
1.1       paf       146: /**
                    147:  * xmlFileMatchWithLocalhostEqDocumentRoot:
                    148:  * filename:  the URI for matching
                    149:  *
                    150:  * check if the URI matches an HTTP one
                    151:  *
                    152:  * Returns 1 if matches, 0 otherwise
                    153:  */
                    154: static int
                    155: xmlFileMatchLocalhost(const char* filename) {
                    156:        if (!strncmp(filename, "http://localhost", 16))
                    157:                return(1);
                    158:        return(0);
                    159: }
                    160: 
                    161: /**
1.15      paf       162:  * xmlFileOpenLocalhost:
1.1       paf       163:  * filename:  the URI for matching
                    164:  *
                    165:  * http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc
                    166:  *
                    167:  * Returns an I/O context or NULL in case of error
                    168:  */
                    169: static void *
                    170: xmlFileOpenLocalhost (const char* filename) {
1.15      paf       171:        return xmlFileOpen_ReadIntoStream(filename, true/*adjust path to root from document_root*/);
1.1       paf       172: }
                    173: 
1.2       paf       174: static int
                    175: xmlFileMatchMethod(const char* filename) {
1.3       paf       176:        if (!strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/))
1.2       paf       177:                return(1);
                    178:        return(0);
                    179: }
                    180: 
1.5       paf       181: /// parser://method/param/here -> ^MAIN:method[/params/here]
1.2       paf       182: static void *
                    183: xmlFileOpenMethod (const char* afilename) {
1.15      paf       184:        const char* buf;
                    185:        try {
                    186:                Request& r=pa_thread_request();
                    187: 
                    188:                char* s=pa_strdup(afilename+9 /*strlen("parser://")*/);
                    189:                const char* method_cstr=lsplit(&s, '/');
                    190:                const String* method=new String(method_cstr);
                    191:                String::Body param_body("/");  
                    192:                if(s)
                    193:                        param_body.append_know_length(s, strlen(s));
                    194: 
                    195:                VString* vparam=new VString(*new String(param_body, String::L_TAINTED));
                    196:                {
                    197:                        Temp_lang temp_lang(r, String::L_XML); // default language: XML
                    198:                        Request::Execute_nonvirtual_method_result body=
                    199:                                r.execute_nonvirtual_method(r.main_class, *method, vparam, true);
                    200:                        if(body.string) {
                    201:                                buf=body.string->cstr(String::L_UNSPECIFIED);
                    202:                        } else
                    203:                                throw Exception(0,
                    204:                                        new String(afilename),
                    205:                                        "'%s' method not found in %s class", 
                    206:                                                        method_cstr, MAIN_CLASS_NAME);
1.2       paf       207:                }
1.15      paf       208:        } catch(const Exception& e) {
                    209:                buf=e.comment();
                    210:        } catch(...) {
                    211:                buf="xmlFileOpenLocalhost: unknown error";
1.2       paf       212:        }
1.15      paf       213:        MemoryStream* stream=new(UseGC) MemoryStream;
                    214:        stream->m_buf=buf;
                    215:        stream->m_size=strlen(buf);
                    216:        return (void *)stream;
1.2       paf       217: }
                    218: 
1.15      paf       219: /**
                    220:  * pa_xmlFileReadMethod:
                    221:  * @context:  the I/O context
                    222:  * @buffer:  where to drop data
                    223:  * @len:  number of bytes to write
                    224:  *
                    225:  * Read @len bytes to @buffer from the I/O channel.
                    226:  *
                    227:  * Returns the number of bytes written
                    228:  */
1.2       paf       229: static int
                    230: pa_xmlFileReadMethod (void * context, //< MemoryStream actually
                    231:                                          char * buffer, int len) 
                    232: {
                    233:        MemoryStream& stream=*static_cast<MemoryStream*>(context);
                    234: 
                    235:        return stream.read(buffer, len);
                    236: }
                    237: 
                    238: static int
                    239: pa_xmlFileCloseMethod (void * /*context*/) {
                    240:        return 0;
                    241: }
                    242: 
                    243: 
1.1       paf       244: 
                    245: void pa_xml_io_init() {
1.17      paf       246:        // file open monitorer [for xslt cacher]
1.9       paf       247:        // safe mode checker, always fail match, but checks non-"://" there
                    248:        xmlRegisterInputCallbacks(
1.17      paf       249:                xmlFileMatchMonitor, xmlFileOpenMonitor,
1.15      paf       250:                pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.17      paf       251: 
1.1       paf       252:        // http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc
                    253:        xmlRegisterInputCallbacks(
                    254:                xmlFileMatchLocalhost, xmlFileOpenLocalhost,
1.8       paf       255:                pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.2       paf       256: 
1.5       paf       257:        // parser://method/param/here -> ^MAIN:method[/params/here]
1.2       paf       258:        xmlRegisterInputCallbacks(
                    259:                xmlFileMatchMethod, xmlFileOpenMethod,
                    260:                pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.1       paf       261: }
                    262: 
                    263: #endif

E-mail: