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

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

E-mail: