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: