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 Massimo Manghi <ma...@unipr.it> on 2008/06/29 18:04:08 UTC

charset handling

I've patched mod_rivet and some related files
in order to have constructs such as

AddType 'application/x-httpd-rivet; charset=utf-8' rvt

be understood and thus to have the default charset
used within rivet templates and scripts changed 
with a single line.

a developer can override the conf line using 
'headers type ....' commands wherever he/she needs
to do it.

To make the debugging easier I also created the boolean
global configuration option 'HonorHeaderOnlyRequests'
(disabled by default).
 
-- Massimo

Index: src/rivet.h
===================================================================
--- src/rivet.h	(revision 669345)
+++ src/rivet.h	(working copy)
@@ -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(\
Index: src/apache-2/mod_rivet.h
===================================================================
--- src/apache-2/mod_rivet.h	(revision 669345)
+++ src/apache-2/mod_rivet.h	(working copy)
@@ -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;
Index: src/apache-2/mod_rivet.c
===================================================================
--- src/apache-2/mod_rivet.c	(revision 669345)
+++ src/apache-2/mod_rivet.c	(working copy)
@@ -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,17 @@
 static int
 Rivet_CheckType (request_rec *req)
 {
-	if ( req->content_type != NULL ) {
-		if( STREQU( req->content_type, "application/x-httpd-rivet")) {
-			return RIVET_FILE;
-		}
+    int	    ctype   = CTYPE_NOT_HANDLED;
 
-		 if( STREQU( req->content_type, "application/x-rivet-tcl")) {
-			return TCL_FILE;
-		}
+    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 +373,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 +432,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 +632,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 +735,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 +832,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 +963,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 +989,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 +1159,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 +1469,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 +1500,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 +1532,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 +1596,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 +1653,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 +1668,6 @@
     return retval;
 }
 
-
 static void
 rivet_register_hooks (apr_pool_t *p)
 {
Index: src/apache-2/TclWebapache.c
===================================================================
--- src/apache-2/TclWebapache.c	(revision 669345)
+++ src/apache-2/TclWebapache.c	(working copy)
@@ -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;
 }
Index: src/TclWeb.h
===================================================================
--- src/TclWeb.h	(revision 669345)
+++ src/TclWeb.h	(working copy)
@@ -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;
 
 /*


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


Re: charset handling

Posted by David Welton <da...@gmail.com>.
I had a very quick look, and these changes look good.  We definitely
need to be careful with the Apache2 code, as the original code commit
definitely had some cruft in it.

-- 
David N. Welton

http://www.welton.it/davidw/

http://www.dedasys.com/

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


Re: charset handling

Posted by Massimo Manghi <ma...@unipr.it>.
A detailed description of the patches sent around in 
my previous message. Regards.

 -- Massimo

2008-06-30 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.




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