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