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