You are viewing a plain text version of this content. The canonical link for it is here.
Posted to rivet-dev@tcl.apache.org by mx...@apache.org on 2008/07/01 22:22:30 UTC

svn commit: r673194 - in /tcl/rivet/trunk: ChangeLog doc/rivet.xml src/TclWeb.h src/apache-2/TclWebapache.c src/apache-2/mod_rivet.c src/apache-2/mod_rivet.h src/rivet.h

Author: mxmanghi
Date: Tue Jul  1 13:22:29 2008
New Revision: 673194

URL: http://svn.apache.org/viewvc?rev=673194&view=rev
Log:

	* src/rivet.h: added macro STRNEQU(s1,s2) which efficiently
	compares 2 strings. Unlike STREQU(s1,s2) this new macro compares
	at most strlen(s2) characters.

	* src/TclWeb.h: added charset field to TclWebRequest. This new
	property gets initialized to NULL every time this structure
	is instantiated. If used it stores a pointer to a string that 
	specifies a header value fragment for the page being generated. 

	* src/apache-2/TclWebapache.c: request_rec is treated as an
	opaque structure and the field 'content_type' is set by calling
	the ap_set_content_type apache core function

	* src/apache-2/mod_rivet.h: a 'honor_header_only_reqs' is added
	to the rivet_server_conf for handling of the 
	HonorHeaderOnlyRequests configuration option

	* src/apache-2/mod_rivet.c: Every content_type is checked 
	for possible charset specifications. When found this is 
	stored in the TclWebRequest structure to be processed later. 
	If a script or template doesn't set a content type on its own (with 
	the 'headers type <ctype>' command) the charset is written in 
	the http headers. Added support for the 'HonorHeaderOnlyRequests' 
	switch. Other minor changes include better code formatting 
	in some functions and commenting out some cruft left around.


Modified:
    tcl/rivet/trunk/ChangeLog
    tcl/rivet/trunk/doc/rivet.xml
    tcl/rivet/trunk/src/TclWeb.h
    tcl/rivet/trunk/src/apache-2/TclWebapache.c
    tcl/rivet/trunk/src/apache-2/mod_rivet.c
    tcl/rivet/trunk/src/apache-2/mod_rivet.h
    tcl/rivet/trunk/src/rivet.h

Modified: tcl/rivet/trunk/ChangeLog
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/ChangeLog?rev=673194&r1=673193&r2=673194&view=diff
==============================================================================
--- tcl/rivet/trunk/ChangeLog (original)
+++ tcl/rivet/trunk/ChangeLog Tue Jul  1 13:22:29 2008
@@ -1,3 +1,31 @@
+2008-07-01 Massimo Manghi <mx...@apache.org>
+	
+	* src/rivet.h: added macro STRNEQU(s1,s2) which efficiently
+	compares 2 strings. Unlike STREQU(s1,s2) this new macro compares
+	at most strlen(s2) characters.
+
+	* src/TclWeb.h: added charset field to TclWebRequest. This new
+	property gets initialized to NULL every time this structure
+	is instantiated. If used it stores a pointer to a string that 
+	specifies a header value fragment for the page being generated. 
+
+	* src/apache-2/TclWebapache.c: request_rec is treated as an
+	opaque structure and the field 'content_type' is set by calling
+	the ap_set_content_type apache core function
+
+	* src/apache-2/mod_rivet.h: a 'honor_header_only_reqs' is added
+	to the rivet_server_conf for handling of the 
+	HonorHeaderOnlyRequests configuration option
+
+	* src/apache-2/mod_rivet.c: Every content_type is checked 
+	for possible charset specifications. When found this is 
+	stored in the TclWebRequest structure to be processed later. 
+	If a script or template doesn't set a content type on its own (with 
+	the 'headers type <ctype>' command) the charset is written in 
+	the http headers. Added support for the 'HonorHeaderOnlyRequests' 
+	switch. Other minor changes include better code formatting 
+	in some functions and commenting out some cruft left around.
+
 2008-01-08 Massimo Manghi <ma...@unipr.it>
 
 	* rivet/packages/dio/dio.tcl: auto_path shouldn't be set 

Modified: tcl/rivet/trunk/doc/rivet.xml
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/doc/rivet.xml?rev=673194&r1=673193&r2=673194&view=diff
==============================================================================
--- tcl/rivet/trunk/doc/rivet.xml (original)
+++ tcl/rivet/trunk/doc/rivet.xml Tue Jul  1 13:22:29 2008
@@ -292,6 +292,7 @@
 	      <arg>UploadMaxSize</arg>
 	      <arg>UploadFilesToVar</arg>
 	      <arg>SeparateVirtualInterps</arg>
+	      <arg>HonorHeaderOnlyRequests</arg>
 	    </group>
 	  </cmdsynopsis>
 	</term>
@@ -535,6 +536,29 @@
 		global level.</para>
 	      </listitem>
 	    </varlistentry>
+
+	    <varlistentry>
+	      <term>
+		<cmdsynopsis>
+		  <arg choice="plain">HonorHeaderOnlyRequests</arg>
+		  <group choice="req">
+		    <arg>yes</arg>
+		    <arg>no</arg>
+		  </group>
+		</cmdsynopsis>
+	      </term>
+	      <listitem>
+		<para>
+		  If a HEAD requests is issued by the client Rivet detects
+		  this case and sends back to the client a standard header 
+		  response. If the real header has to be examined (e.g. 
+		  for debugging) you can turn on this options which 
+		  causes Rivet to parse and run the script the requests refers 
+		  to. In this case the real header is returned to the client.
+		</para>
+		<para>This option is, by nature, only available at the global level</para>
+	      </listitem>
+	    </varlistentry>
 	  </variablelist>
 	</listitem>
       </varlistentry>
@@ -1390,7 +1414,6 @@
 
       <refsect1>
 	<title>Description</title>
-
 	<para>
 	  This command is useful for situations where it is necessary
 	  to only return HTTP headers and no actual content.  For
@@ -1747,48 +1770,56 @@
 	abilty of JavaScript (and other scriping languages like VBScript) to 
 	manipulate dynamically the HTML structure of a page. In modern browsers 
 	JavaScript code is enabled to send GET or POST requests to the webserver.
-	These requests can ask the server to run scripts (for example Rivet
-	Tcl scripts) that build responses and send them back to the browser.
+	These requests can request the server to run scripts (for example Rivet
+	Tcl scripts) that build responses and to be sent back to the browser.
 	JavaScript code reads asynchronously these responses, elaborates
 	their content and accordingly modifies the page on display. 
 	Ajax helps to build web applications that are more responsive and 
-	flexible. Instead of going through the cycle of request-generation-transfer
+	flexible, if you can cope with the complexities, subtleties and 
+	incompatibilities even among the most common browsers available. 
+	Instead of going through the cycle of request-generation-transfer
 	of a page, Ajax allows the programmer to request and transmit only
 	the essential data thus matching the general requirement of separation
 	between data and user interface (and saving the server from sending over
-	the same html code and graphics every time a page is refreshed)
+	the same html code and graphics when only a fraction of a page has
+	to be refreshed)
       </para>
       <para>
 	In Ajax	applications the communication between client and server 
 	is controlled by an instance of a specialized object: the non-IE world
-	uses the XMLHttpRequest class to create it, 
-	whereas IE uses the ActiveXObject class. Through an instance of
-	that class a POST or GET request is sent to the server, which in turn
-	responds with a message that is stored as a string in a property of the 
-	communication object called 'returnedText'. 
-	Although this sort of communication channel doesn't imply that the messages
-	being transmitted through it have a specific protocol, it's become widely
-	customary to use XML as the format for such messages. A number
-	of XML specification are being used for this, among which XML-RPC and
-	SOAP are worth to be quoted. Anyway, you can invent your own protocol
-	(either based on XML or anything else), but one has to be aware of the fact 
-	that if the http headers are properly set and the message returned 
-	to the client is a well formed XML fragment, also the property 
+	(Firefox,Safari,Opera...) uses the XMLHttpRequest class to create it, 
+	whereas IE uses the ActiveXObject class.
+      	<note>
+	    With the release of IE7 Microsoft introduced 
+	    <ulink url="http://blogs.msdn.com/ie/archive/2006/01/23/516393.aspx">
+	    native support</ulink> for XMLHttpRequest class objects
+      	</note>	
+	By creating an instance of this class a POST or GET request can be sent 
+	to the server, whose response is stored in a 
+	property ('returnedText') of the communication object. 
+	It's become widely customary to encode in XML messages the response
+	from the server to the browser. A number of XML specification are 
+	being used for this, among which XML-RPC and SOAP are worth to be 
+	quoted. Anyway, you can invent your own message definitions
+	(either based on XML or anything else), but one has to be aware of 
+	the fact that if the http headers are properly set and the message 
+	returned to the client is a well formed XML fragment, also the property 
 	<ulink url="http://www.w3schools.com/ajax/ajax_responsexml.asp">
 	XMLResponse</ulink> is set with a reference to an object 
-	that stores the response as an XML document. This object is an 
-	instance of a class that implements the
+	that represent the
 	<ulink url="http://www.w3schools.com/dom/default.asp">
-	XML W3C DOM</ulink> tree methods and properties, thus
-	enabling the scripts to read and manipulate the data embedded in 
-	the XML message with a structured and standard interface.
+	DOM</ulink> of the XML response. 
+	By means of the XML W3C DOM tree methods and properties
+	you can write scripts that read and manipulate the data embedded in 
+	the XML message.
       </para>
       <para>
         In this example a Rivet script initializes an array with the
 	essential data regarding a few of the major composers of the 
 	european music. This array plays the role of a database
-	which, in a real case, might store large tables with thousands 
-	records and more complete and extended information. 
+	which, in a real case, has is a real DBM which stores large 
+	tables with thousands records and more complex and 
+	extended information. 
 	The script is designed to send back to the client two 
 	types of responses: a catalog of the composers or a single 
 	record of a composer.

Modified: tcl/rivet/trunk/src/TclWeb.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/TclWeb.h?rev=673194&r1=673193&r2=673194&view=diff
==============================================================================
--- tcl/rivet/trunk/src/TclWeb.h (original)
+++ tcl/rivet/trunk/src/TclWeb.h Tue Jul  1 13:22:29 2008
@@ -32,6 +32,7 @@
     int headers_set;		/* has the header been set yet? */
     int content_sent;
     int environment_set;	/* have we setup the environment variables? */
+    char* charset;
 } TclWebRequest;
 
 /*

Modified: tcl/rivet/trunk/src/apache-2/TclWebapache.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/apache-2/TclWebapache.c?rev=673194&r1=673193&r2=673194&view=diff
==============================================================================
--- tcl/rivet/trunk/src/apache-2/TclWebapache.c (original)
+++ tcl/rivet/trunk/src/apache-2/TclWebapache.c Tue Jul  1 13:22:29 2008
@@ -87,7 +87,8 @@
     if(req->headers_set)
         return TCL_ERROR;
 
-    req->req->content_type = (char *) apr_pstrdup(req->req->pool, header);
+//    req->req->content_type = (char *) apr_pstrdup(req->req->pool, header);
+    ap_set_content_type(req->req,header);
     req->headers_set = 1;
     return TCL_OK;
 }

Modified: tcl/rivet/trunk/src/apache-2/mod_rivet.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/apache-2/mod_rivet.c?rev=673194&r1=673193&r2=673194&view=diff
==============================================================================
--- tcl/rivet/trunk/src/apache-2/mod_rivet.c (original)
+++ tcl/rivet/trunk/src/apache-2/mod_rivet.c Tue Jul  1 13:22:29 2008
@@ -57,8 +57,7 @@
 
 //module AP_MODULE_DECLARE_DATA rivet_module;
 
-/* This is used *only* in the PanicProc.  Otherwise, don't touch
- * it! */
+/* This is used *only* in the PanicProc.  Otherwise, don't touch it! */
 static request_rec *globalrr;
 
 /* Need some arbitrary non-NULL pointer which can't also be a request_rec */
@@ -66,8 +65,9 @@
 #define DEBUG(s) fprintf(stderr, s), fflush(stderr)
 
 /* rivet or tcl file */
-#define RIVET_FILE 1
-#define TCL_FILE 2
+#define CTYPE_NOT_HANDLED   0
+#define RIVET_FILE	    1
+#define TCL_FILE	    2
 
 /* rivet return codes */
 #define RIVET_OK 0
@@ -77,23 +77,25 @@
 
 /* This snippet of code came from the mod_ruby project, which is under a BSD license. */
 #ifdef APACHE2 /* Apache 2.x */
-	
+
+#define RIVET_FILE_CTYPE	"application/x-httpd-rivet"
+#define TCL_FILE_CTYPE		"application/x-rivet-tcl"
 
 static void ap_chdir_file(const char *file)
 {
-	const  char *x;
-	char chdir_buf[HUGE_STRING_LEN];
-	x = strrchr(file, '/');
-	if (x == NULL) {
-		chdir(file);
-	}
-	else if (x - file < sizeof(chdir_buf) - 1) {
-		memcpy(chdir_buf, file, x - file);
-		chdir_buf[x - file] = '\0';
-		chdir(chdir_buf);
-	}
+    const  char *x;
+    char chdir_buf[HUGE_STRING_LEN];
+    x = strrchr(file, '/');
+    if (x == NULL) {
+	chdir(file);
+    } else if (x - file < sizeof(chdir_buf) - 1) {
+	memcpy(chdir_buf, file, x - file);
+	chdir_buf[x - file] = '\0';
+	chdir(chdir_buf);
+    }
 }
 #endif
+
 /* Function to be used should we desire to upload files to a variable */
 
 #if 0
@@ -116,16 +118,16 @@
 static int
 Rivet_CheckType (request_rec *req)
 {
-	if ( req->content_type != NULL ) {
-		if( STREQU( req->content_type, "application/x-httpd-rivet")) {
-			return RIVET_FILE;
-		}
-
-		 if( STREQU( req->content_type, "application/x-rivet-tcl")) {
-			return TCL_FILE;
-		}
+    int	ctype = CTYPE_NOT_HANDLED;
+
+    if ( req->content_type != NULL ) {
+	if( STRNEQU( req->content_type, RIVET_FILE_CTYPE) ) {
+	    ctype  = RIVET_FILE;
+	} else if( STRNEQU( req->content_type, TCL_FILE_CTYPE) ) {
+	    ctype = TCL_FILE;
+	} 
     }
-	return 0; 
+    return ctype; 
 }
 /*
  * Rivet_ParseFileArgString (char *szDocRoot, char *szArgs, char **file)
@@ -370,15 +372,16 @@
 
     /* Make sure to flush the output if buffer_add was the only output */
 good:
+
+    if (!globals->req->headers_set && (globals->req->charset != NULL)) {
+    	TclWeb_SetHeaderType (apr_pstrcat(globals->req->req->pool,"text/html;",globals->req->charset),globals->req);
+    }
     TclWeb_PrintHeaders(globals->req);
     Tcl_Flush(*(conf->outchannel));
 
     return TCL_OK;
 }
 
-
-
-
 /* This is a separate function so that it may be called from 'Parse' */
 int
 Rivet_ParseExecFile(TclWebRequest *req, char *filename, int toplevel)
@@ -428,7 +431,6 @@
         *(rsc->cache_free) = *(rsc->cache_size);
     }
 
-
     /* If toplevel is 0, we are being called from Parse, which means
        we need to get the information about the file ourselves. */
     if (toplevel == 0)
@@ -629,6 +631,7 @@
     newrsc->upload_max = oldrsc->upload_max;
     newrsc->upload_files_to_var = oldrsc->upload_files_to_var;
     newrsc->separate_virtual_interps = oldrsc->separate_virtual_interps;
+    newrsc->honor_header_only_reqs = oldrsc->honor_header_only_reqs;
     newrsc->server_name = oldrsc->server_name;
     newrsc->upload_dir = oldrsc->upload_dir;
     newrsc->rivet_server_vars = oldrsc->rivet_server_vars;
@@ -731,6 +734,7 @@
     rsc->upload_max = 0;
     rsc->upload_files_to_var = 0;
     rsc->separate_virtual_interps = 0;
+    rsc->honor_header_only_reqs = 0;
     rsc->server_name = NULL;
     rsc->upload_dir = "/tmp";
     rsc->objCacheList = NULL;
@@ -827,8 +831,7 @@
 
     /* Create TCL commands to deal with Apache's BUFFs. */
     rsc->outchannel = apr_pcalloc(p, sizeof(Tcl_Channel));
-    *(rsc->outchannel) = Tcl_CreateChannel(&RivetChan, "apacheout", rsc,
-            TCL_WRITABLE);
+    *(rsc->outchannel) = Tcl_CreateChannel(&RivetChan, "apacheout", rsc, TCL_WRITABLE);
 
     Tcl_SetStdChannel(*(rsc->outchannel), TCL_STDOUT);
 
@@ -959,7 +962,8 @@
  * 	RivetServerConf UploadMaxSize <integer>
  * 	RivetServerConf UploadFilesToVar <yes|no>
  * 	RivetServerConf SeparateVirtualInterps <yes|no>
-*/
+ * 	RivetServerConf HonorHeaderOnlyRequests <yes|no> (2008-06-20: mm)
+ */
 
 static const char *
 Rivet_ServerConf( cmd_parms *cmd, void *dummy, char *var, char *val )
@@ -984,6 +988,8 @@
         Tcl_GetBoolean (NULL, val, &rsc->upload_files_to_var);
     } else if( STREQU( var, "SeparateVirtualInterps" ) ) {
         Tcl_GetBoolean (NULL, val, &rsc->separate_virtual_interps);
+    } else if( STREQU( var, "HonorHeaderOnlyRequests" ) ) {
+        Tcl_GetBoolean (NULL, val, &rsc->honor_header_only_reqs);
     } else {
         string = Rivet_SetScript( cmd->pool, rsc, var, val);
     }
@@ -1152,6 +1158,7 @@
         overrides->upload_max : base->upload_max;
 
     rsc->separate_virtual_interps = base->separate_virtual_interps;
+    rsc->honor_header_only_reqs = base->honor_header_only_reqs;
 
     /* server_name is set up later. */
 
@@ -1461,21 +1468,24 @@
 static int
 Rivet_SendContent(request_rec *r)
 {
-    char error[MAX_STRING_LEN];
-    char timefmt[MAX_STRING_LEN];
+//    char error[MAX_STRING_LEN];
+//    char timefmt[MAX_STRING_LEN];
     int errstatus;
     int retval;
+    int ctype;
 
-    Tcl_Interp	*interp;
-    static Tcl_Obj	*request_init = NULL;
-    static Tcl_Obj	*request_cleanup = NULL;
+    Tcl_Interp		*interp;
+    static Tcl_Obj 	*request_init = NULL;
+    static Tcl_Obj 	*request_cleanup = NULL;
 
     rivet_interp_globals *globals = NULL;
-    rivet_server_conf *rsc = NULL;
-    rivet_server_conf *rdc;
+    rivet_server_conf 	*rsc = NULL;
+    rivet_server_conf 	*rdc;
 
-    if (!Rivet_CheckType(r))
+    ctype = Rivet_CheckType(r);  
+    if (ctype == CTYPE_NOT_HANDLED) {
         return DECLINED;
+    }
 
     Tcl_MutexLock(&sendMutex);
 
@@ -1489,6 +1499,10 @@
     globals->r = r;
     globals->req = (TclWebRequest *)apr_pcalloc(r->pool, sizeof(TclWebRequest));
 
+/* we will test against NULL to check if a charset was specified in the conf */
+
+    globals->req->charset = NULL;
+
     if (r->per_dir_config != NULL)
         rdc = RIVET_SERVER_CONF( r->per_dir_config );
     else
@@ -1517,8 +1531,8 @@
         goto sendcleanup;
     }
 
-    apr_cpystrn(error, DEFAULT_ERROR_MSG, sizeof(error));
-    apr_cpystrn(timefmt, DEFAULT_TIME_FORMAT, sizeof(timefmt));
+//    apr_cpystrn(error, DEFAULT_ERROR_MSG, sizeof(error));
+//    apr_cpystrn(timefmt, DEFAULT_TIME_FORMAT, sizeof(timefmt));
 
     /* This one is the big catch when it comes to moving towards
        Apache 2.0, or one of them, at least. */
@@ -1581,12 +1595,50 @@
         goto sendcleanup;
     }
 
-    if (r->header_only)
+    if (r->header_only && !rsc->honor_header_only_reqs)
     {
         TclWeb_SetHeaderType(DEFAULT_HEADER_TYPE, globals->req);
         TclWeb_PrintHeaders(globals->req);
         retval = OK;
         goto sendcleanup;
+    } 
+
+/* 
+ * if we are handling the request we also want to check if a charset 
+ * parameter was set with the content type, e.g. rivet's configuration 
+ * or .htaccess had lines like 
+ *
+ * AddType 'application/x-httpd-rivet; charset=utf-8;' rvt 
+ */
+ 
+/*
+ * if strlen(req->content_type) > strlen([RIVET|TCL]_FILE_CTYPE)
+ * a charset parameters might be there 
+ */
+
+    {
+	int content_type_len = strlen(r->content_type);
+
+	if (((ctype==RIVET_FILE) && (content_type_len > strlen(RIVET_FILE_CTYPE))) || \
+	     ((ctype==TCL_FILE)  && (content_type_len > strlen(TCL_FILE_CTYPE)))) {
+	    
+	    char* charset;
+
+	    /* we parse the content type: we are after a 'charset' parameter definition */
+		
+	    charset = strstr(r->content_type,"charset");
+	    if (charset != NULL) {
+		charset = apr_pstrdup(r->pool,charset);
+
+	    /* ther's some freedom about spaces in the AddType lines: let's strip them off */
+
+		apr_collapse_spaces(charset,charset);
+		globals->req->charset = charset;
+
+		fprintf(stderr,"%s\n",charset);
+		fflush(stderr);
+	    }
+	}
     }
 
     if (Rivet_ParseExecFile(globals->req, r->filename, 1) != TCL_OK)
@@ -1600,7 +1652,7 @@
         Tcl_IncrRefCount(request_cleanup);
     }
 
-    if(Tcl_EvalObjEx(interp, request_cleanup, 0) == TCL_ERROR) {
+    if (Tcl_EvalObjEx(interp, request_cleanup, 0) == TCL_ERROR) {
         ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r->server, "%s",
                 Tcl_GetVar(interp, "errorInfo", 0));
     }
@@ -1615,7 +1667,6 @@
     return retval;
 }
 
-
 static void
 rivet_register_hooks (apr_pool_t *p)
 {

Modified: tcl/rivet/trunk/src/apache-2/mod_rivet.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/apache-2/mod_rivet.h?rev=673194&r1=673193&r2=673194&view=diff
==============================================================================
--- tcl/rivet/trunk/src/apache-2/mod_rivet.h (original)
+++ tcl/rivet/trunk/src/apache-2/mod_rivet.h Tue Jul  1 13:22:29 2008
@@ -76,6 +76,7 @@
     int upload_max;
     int upload_files_to_var;
     int separate_virtual_interps;
+    int honor_header_only_reqs;			/* default: 0 */
     char *server_name;
     char *upload_dir;
     apr_table_t *rivet_server_vars;

Modified: tcl/rivet/trunk/src/rivet.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/rivet.h?rev=673194&r1=673193&r2=673194&view=diff
==============================================================================
--- tcl/rivet/trunk/src/rivet.h (original)
+++ tcl/rivet/trunk/src/rivet.h Tue Jul  1 13:22:29 2008
@@ -5,7 +5,8 @@
 #define TCL_STORAGE_CLASS DLLEXPORT
 #endif /* BUILD_rivet */
 
-#define STREQU(s1, s2) (s1[0] == s2[0] && strcmp(s1, s2) == 0)
+#define STREQU(s1, s2)  (s1[0] == s2[0] && strcmp(s1, s2) == 0)
+#define STRNEQU(s1, s2) (s1[0] == s2[0] && strncmp(s1, s2, strlen(s2)) == 0)
 
 #define TCL_CMD_HEADER(cmd)	\
 static int cmd(\



---------------------------------------------------------------------
To unsubscribe, e-mail: rivet-cvs-unsubscribe@tcl.apache.org
For additional commands, e-mail: rivet-cvs-help@tcl.apache.org