Annotation of parser3/src/main/pa_xml_io.C, revision 1.36
1.1 paf 1: /** @file
2: Parser: plugins to xml library, controlling i/o; implementation
3:
1.33 moko 4: Copyright (c) 2001-2017 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.36 ! moko 12: volatile const char * IDENT_PA_XML_IO_C="$Id: pa_xml_io.C,v 1.35 2019/11/05 16:50:30 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.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
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.35 moko 63: static void * xmlFileOpen_ReadIntoStream (const char* do_not_store_filename, bool adjust_path_to_root_from_document_root=false) {
1.18 paf 64: #ifdef PA_SAFE_MODE
65: //copied from libxml/catalog.c
66: # define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
67: // disable attempts to consult default catalog [usually, that file belongs to other user/group]
68: if(strcmp(do_not_store_filename, XML_XML_DEFAULT_CATALOG)==0)
69: return 0;
70: #endif
71:
1.15 paf 72: Request& r=pa_thread_request();
1.35 moko 73: char adjust_buf[MAX_STRING];
1.15 paf 74: if(adjust_path_to_root_from_document_root) {
75: const char* document_root=r.request_info.document_root;
76: if(!document_root)
77: document_root=".";
78:
79: adjust_buf[0]=0;
80: strcat(adjust_buf, document_root);
1.17 paf 81: strcat(adjust_buf, &do_not_store_filename[16]);
82: do_not_store_filename=adjust_buf;
1.15 paf 83: } else
1.30 moko 84: if(!strstr(do_not_store_filename, "http://")) {
85: if(strstr(do_not_store_filename, "file://")) {
1.35 moko 86: do_not_store_filename+=7 /*strlen("file://")*/;
1.26 misha 87: #ifdef WIN32
88: if(
89: do_not_store_filename[0]=='/'
90: && do_not_store_filename[1]
91: && do_not_store_filename[2]==':'
92: && do_not_store_filename[3]=='/'
1.30 moko 93: ) {
1.26 misha 94: // skip leading slash for absolute path file:///C:/path/to/file
95: do_not_store_filename++;
96: }
97: #endif
1.30 moko 98: } else if(*do_not_store_filename && do_not_store_filename[1]!=':' && strstr(do_not_store_filename, "://")) {
1.20 misha 99: pa_xmlStopMonitoringDependencies();
100: return 0; // plug out [do not handle other prefixes]
101: }
1.30 moko 102: }
1.17 paf 103:
104: const char* can_store_filename=pa_strdup(do_not_store_filename);
105: add_dependency(can_store_filename);
1.15 paf 106:
107: const char *buf;
108: try {
1.23 misha 109: buf=file_load_text(r, *new String(can_store_filename),
1.35 moko 110: true /*fail_on_read_problem*/,
111: 0 /*params*/,
112: false /*don't transcode result because it must be fit with @encoding value!*/);
1.15 paf 113: } catch(const Exception& e) {
1.17 paf 114: if(strcmp(e.type(), "file.missing")==0)
115: return 0; // let the library try that and report an error properly
116:
1.15 paf 117: buf=e.comment();
118: } catch(...) {
1.17 paf 119: buf="xmlFileOpen_ReadIntoStream: unknown error";
1.15 paf 120: }
1.36 ! moko 121: return (void *)new MemoryStream(buf);
1.15 paf 122: }
1.9 paf 123:
1.35 moko 124: static int xmlFileMatchMonitor(const char* /*file_spec_cstr*/) {
1.17 paf 125: return 1; // always intercept, causing xmlFileOpenMonitor to be called
1.15 paf 126: }
1.35 moko 127:
128: static void *xmlFileOpenMonitor(const char* filename) {
1.15 paf 129: return xmlFileOpen_ReadIntoStream(filename); // handles localfile case, else returns 0
1.9 paf 130: }
131:
1.1 paf 132: /**
133: * xmlFileMatchWithLocalhostEqDocumentRoot:
134: * filename: the URI for matching
135: *
136: * check if the URI matches an HTTP one
137: *
138: * Returns 1 if matches, 0 otherwise
139: */
1.35 moko 140: static int xmlFileMatchLocalhost(const char* filename) {
141: return !strncmp(filename, "http://localhost", 16);
1.1 paf 142: }
143:
144: /**
1.15 paf 145: * xmlFileOpenLocalhost:
1.1 paf 146: * filename: the URI for matching
147: *
148: * http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc
149: *
150: * Returns an I/O context or NULL in case of error
151: */
1.35 moko 152: static void *xmlFileOpenLocalhost(const char* filename) {
1.15 paf 153: return xmlFileOpen_ReadIntoStream(filename, true/*adjust path to root from document_root*/);
1.1 paf 154: }
155:
1.35 moko 156: static int xmlFileMatchMethod(const char* filename) {
157: return !strncmp(filename, "parser://", 9 /*strlen("parser://"), and check xmlFileOpenMethod*/);
1.2 paf 158: }
159:
1.5 paf 160: /// parser://method/param/here -> ^MAIN:method[/params/here]
1.35 moko 161: static void *xmlFileOpenMethod (const char* afilename) {
1.15 paf 162: const char* buf;
163: try {
164: Request& r=pa_thread_request();
165:
166: char* s=pa_strdup(afilename+9 /*strlen("parser://")*/);
167: const char* method_cstr=lsplit(&s, '/');
168: const String* method=new String(method_cstr);
169: String::Body param_body("/");
170: if(s)
171: param_body.append_know_length(s, strlen(s));
172:
173: VString* vparam=new VString(*new String(param_body, String::L_TAINTED));
1.32 moko 174: Request::Execute_nonvirtual_method_result body=r.execute_nonvirtual_method(r.main_class, *method, vparam, true);
175: if(body.string) {
176: buf=body.string->untaint_cstr(String::L_XML);
177: } else
178: throw Exception(0, new String(afilename), "'%s' method not found in %s class", method_cstr, MAIN_CLASS_NAME);
1.15 paf 179: } catch(const Exception& e) {
180: buf=e.comment();
181: } catch(...) {
182: buf="xmlFileOpenLocalhost: unknown error";
1.2 paf 183: }
1.36 ! moko 184: return (void *)new MemoryStream(buf);
1.2 paf 185: }
186:
1.15 paf 187: /**
188: * pa_xmlFileReadMethod:
189: * @context: the I/O context
190: * @buffer: where to drop data
191: * @len: number of bytes to write
192: *
193: * Read @len bytes to @buffer from the I/O channel.
194: *
195: * Returns the number of bytes written
196: */
1.35 moko 197: static int pa_xmlFileReadMethod (void* context, char* buffer, int len){
1.2 paf 198: MemoryStream& stream=*static_cast<MemoryStream*>(context);
199: return stream.read(buffer, len);
200: }
201:
1.35 moko 202: static int pa_xmlFileCloseMethod (void* /*context*/) {
1.2 paf 203: return 0;
204: }
205:
1.1 paf 206: void pa_xml_io_init() {
1.17 paf 207: // file open monitorer [for xslt cacher]
1.9 paf 208: // safe mode checker, always fail match, but checks non-"://" there
1.35 moko 209: xmlRegisterInputCallbacks(xmlFileMatchMonitor, xmlFileOpenMonitor, pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.17 paf 210:
1.1 paf 211: // http://localhost/abc -> $ENV{DOCUMENT_ROOT}/abc | ./abc
1.35 moko 212: xmlRegisterInputCallbacks(xmlFileMatchLocalhost, xmlFileOpenLocalhost, pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.2 paf 213:
1.5 paf 214: // parser://method/param/here -> ^MAIN:method[/params/here]
1.35 moko 215: xmlRegisterInputCallbacks(xmlFileMatchMethod, xmlFileOpenMethod, pa_xmlFileReadMethod, pa_xmlFileCloseMethod);
1.1 paf 216: }
217:
218: #endif
E-mail: