httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jeff Trawick <trawi...@bellsouth.net>
Subject [PATCH] (big) buff.c/buff.h translation cleanup
Date Wed, 10 May 2000 03:03:02 GMT
Yes, this is a big patch :(  This has various changes Greg Ames and I
have been working on since we started porting 2.0 to OS/390.

major issues addressed:

1) translation generality

  previously, buff operations could only use hard-coded translation
  mechanisms; they had a binary flag for whether or not to translate
  on read and a binary flag for whether or not to translate on write;
  now, a translation handle is available so that arbitrary
  APR-provided translations can be performed (but: non-SBCS capability
  isn't handled yet)

somewhat-major issues addressed:

1) when the configuration supports translation (i.e., APACHE_XLATE is
   defined), some function pointers are used for key buff operations
   (current ap_bread() and ap_bwrite()) so that translation code can
   be separated from buffer management code and so that the code
   doesn't have to check for whether or not it should translating

   e.g., when translation is on, ap_bwrite() uses a pointer in BUFF
   which points to ap_bwrite_xlate(), which always does translation;
   it calls ap_bwrite_core(), which never does translation; when
   translation is off, the pointer in BUFF used by ap_bwrite() points
   directly to ap_bwrite_core()

   As far as I can tell, this is one of Martin's ideas posted recently
   for how to clean up the translation.

minor issues addressed:

1) 1.3 translation support kept a single buffer per httpd process for
   translating in ap_bwrite(); now there is one buffer per BUFF so
   that it is thread-safe

2) feature tests:

   keep putting code that is EBCDIC-specific inside ifdef
   CHARSET_EBCDIC, but use APACHE_XLATE for generic translation code

3) restore some code that was lost in 2.0 for unknown reasons

   (e.g., ap_bgetc() et al)

4) put in one or two late-1.3 EBCDIC fixes

-------

todos: 

  fix up ap_bread_xlate() and ap_bwrite_xlate() to handle non-SBCS
    (hopefully not many more primitives will have to handle it, but
    then maybe I'm hopelessly naive)

  look further into Martin's ideas for the bottom layer of buff;
    ap_bread_xlate() helped clean up ap_bread() considerably because the
    translation logic was sprinkled all over the function; however, it
    is now slower in many cases (we don't copy as we translate but
    instead copy first then translate); if ap_bread_xlate() and
    ap_bread_core() could call something that just made bytes
    available but didn't copy, then we wouldn't have to touch the
    storage as much on the translate path

-------

impacts to non-translating configurations (i.e., when neither
APACHE_XLATE or CHARSET_EBCDIC is defined):

. no extra storage
. no extra pathlength
. no different code executed
. ap_bread() and ap_bwrite() are macros which map to ap_bread_core()
  and ap_bwrite_core()

Index: src/include/ap_ac_config.h
===================================================================
RCS file: /cvs/apache/apache-2.0/src/include/ap_ac_config.h,v
retrieving revision 1.15
diff -u -r1.15 ap_ac_config.h
--- ap_ac_config.h	2000/05/04 04:02:14	1.15
+++ ap_ac_config.h	2000/05/10 02:32:16
@@ -233,4 +233,8 @@
 #undef USE_MMAP_FILES
 #endif
 
+#if defined(CHARSET_EBCDIC) && !defined(APACHE_XLATE)
+#define APACHE_XLATE
+#endif
+
 #endif /* AP_AC_CONFIG_H */
Index: src/include/buff.h
===================================================================
RCS file: /cvs/apache/apache-2.0/src/include/buff.h,v
retrieving revision 1.19
diff -u -r1.19 buff.h
--- buff.h	2000/04/14 15:58:16	1.19
+++ buff.h	2000/05/10 02:32:16
@@ -69,7 +69,10 @@
 #include "ap_iol.h"
 #include "apr_lib.h"
 #include "apr_general.h"
-
+#ifdef APACHE_XLATE
+#include "apr_xlate.h"
+#endif
+    
 /*
     A BUFF is an i/o object which can be used in any of the following
     output modes:
@@ -129,6 +132,13 @@
 
 typedef struct buff_struct BUFF;
 
+#ifdef APACHE_XLATE
+typedef struct biol {
+    ap_status_t (*bwrite)(BUFF *, const void *, ap_size_t, ap_ssize_t *);
+    ap_status_t (*bread)(BUFF *, const void *, ap_size_t, ap_ssize_t *);
+} biol;
+#endif /*APACHE_XLATE*/
+
 struct buff_struct {
     int flags;			/* flags */
     ap_status_t saved_errno;	/* saved errno */
@@ -156,6 +166,21 @@
     ap_pool_t *pool;
 
     ap_iol *iol;
+#ifdef APACHE_XLATE
+    biol biol;
+    ap_xlate_t *write_xlate;
+    ap_xlate_t *read_xlate;
+    char *xbuf;                 /* buffer to use temporarily while translating */
+    size_t xbufsize;            /* size of xbuf buffer */
+    unsigned char last_getc_raw; /* last character retrieved via ap_bgetc(), before
+                                  * translation; because read translation may be
+                                  * different than write translation, we can't use
+                                  * a write translation handle to put back what
+                                  * we previously translated with the read
+                                  * translation handle; thus, we need the
+                                  * untranslated version in case ap_bungetc() is
+                                  * called */
+#endif /*APACHE_XLATE*/
 };
 
 /* Options to bset/getopt */
@@ -169,6 +194,18 @@
 */
 #define BO_TIMEOUT (2)
 #define BO_ERROR (3)
+#ifdef APACHE_XLATE
+/* BO_WXLATE - translate-charset-on-write setting; if value is NULL, no
+ *             translation is performed; otherwise, value is ap_xlate_t * and
+ *             translation will be performed
+ */
+#define BO_WXLATE (4)
+/* BO_RXLATE - translate-charset-on-read setting; if value is NULL, no
+ *             translation is performed; otherwise, value is ap_xlate_t * and
+ *             translation will be performed
+ */
+#define BO_RXLATE (5)
+#endif /*APACHE_XLATE*/
 
 /* Stream creation and modification */
 API_EXPORT(BUFF *) ap_bcreate(ap_pool_t *p, int flags);
@@ -196,7 +233,7 @@
  * *bytes_read is set to the number of bytes read.  it is possible for
  * bytes to have been read even if an error (or APR_EOF) is returned.
  */
-API_EXPORT(ap_status_t) ap_bread(BUFF *fb, void *buf, ap_size_t nbyte,
+API_EXPORT(ap_status_t) ap_bread_core(BUFF *fb, void *buf, ap_size_t nbyte,
                                  ap_ssize_t *bytes_read);
 API_EXPORT(int) ap_bgets(char *s, int n, BUFF *fb);
 API_EXPORT(int) ap_blookc(BUFF *fb);
@@ -204,8 +241,20 @@
  * *bytes_written is set to the number of bytes written.  it is possible
  * for both an error to be returned, and bytes to have been written.
  */
-API_EXPORT(ap_status_t) ap_bwrite(BUFF *fb, const void *buf, ap_size_t nbyte,
+API_EXPORT(ap_status_t) ap_bwrite_core(BUFF *fb, const void *buf, ap_size_t nbyte,
                                   ap_ssize_t *bytes_written);
+#ifdef APACHE_XLATE
+#define ap_bwrite(fb,buf,nbyte,bytes_written) \
+(fb)->biol.bwrite(fb,buf,nbyte,bytes_written)
+#define ap_bread(fb,buf,nbyte,bytes_read) \
+(fb)->biol.bread(fb,buf,nbyte,bytes_read)
+#else /*APACHE_XLATE*/
+#define ap_bwrite(fb,buf,nbyte,bytes_written) \
+ap_bwrite_core(fb,buf,nbyte,bytes_written)
+#define ap_bread(fb,buf,nbyte,bytes_read) \
+ap_bread_core(fb,buf,nbyte,bytes_read)
+#endif /*APACHE_XLATE*/
+    
 API_EXPORT(ap_status_t) ap_bflush(BUFF *fb);
 API_EXPORT(ap_status_t) ap_bshutdown(BUFF *fb, int how);
 API_EXPORT(int) ap_bputs(const char *x, BUFF *fb);
@@ -218,6 +267,8 @@
 API_EXPORT(int) ap_bflsbuf(int c, BUFF *fb);
 API_EXPORT(int) ap_bfilbuf(BUFF *fb);
 
+#ifndef APACHE_XLATE
+  
 #define ap_bgetc(fb)   ( ((fb)->incnt == 0) ? ap_bfilbuf(fb) : \
 		    ((fb)->incnt--, *((fb)->inptr++)) )
 
@@ -228,6 +279,25 @@
 #define ap_bputc(c, fb) ((((fb)->flags & (B_EOUT|B_WRERR|B_WR)) != B_WR || \
 		     (fb)->outcnt == (fb)->bufsiz) ? ap_bflsbuf(c, (fb)) : \
 		     ((fb)->outbase[(fb)->outcnt++] = (c), 0))
+
+#else /*APACHE_XLATE*/
+ 
+/* can only unput a single character that was read by ap_bgetc */
+#define ap_bungetc(c, fb)  ((fb)->incnt++, \
+                    *(--(fb)->inptr) = (fb)->last_getc_raw)
+			
+#define ap_bgetc(fb)   ( ((fb)->incnt == 0) ? (fb)->last_getc_raw = ap_bfilbuf(fb)
: \
+                    ((fb)->incnt--, (fb)->last_getc_raw = *((fb)->inptr++), \
+                    ((fb)->read_xlate)\
+                    ?ap_xlate_conv_byte((fb)->read_xlate,(fb)->last_getc_raw): \
+                    (fb)->last_getc_raw) )
+ 
+#define ap_bputc(c, fb) ((((fb)->flags & (B_EOUT|B_WRERR|B_WR)) != B_WR || \
+                     (fb)->outcnt == (fb)->bufsiz) ? ap_bflsbuf(c, (fb)) : \
+                     ((fb)->outbase[(fb)->outcnt++] = ((fb)->write_xlate)\
+                     ?ap_xlate_conv_byte((fb)->write_xlate,(unsigned char)c):(c), 0))
+ 
+#endif /*APACHE_XLATE*/
 
 API_EXPORT(int) ap_bspawn_child(ap_pool_t *, int (*)(void *, ap_child_info_t *), void *,
 					enum kill_conditions, BUFF **pipe_in, BUFF **pipe_out,
Index: src/main/buff.c
===================================================================
RCS file: /cvs/apache/apache-2.0/src/main/buff.c,v
retrieving revision 1.38
diff -u -r1.38 buff.c
--- buff.c	2000/04/20 15:20:31	1.38
+++ buff.c	2000/05/10 02:32:18
@@ -60,6 +60,7 @@
 #include "httpd.h"
 #include "http_main.h"
 #include "http_log.h"
+#include "util_ebcdic.h"
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -113,6 +114,13 @@
  *   keep a stack of routines to call on error.
  */
 
+#ifdef APACHE_XLATE
+static ap_status_t ap_bwrite_xlate(BUFF *fb, const void *buf, ap_size_t nbyte,
+                                  ap_ssize_t *bytes_written);
+static ap_status_t ap_bread_xlate(BUFF *fb, void *buf, ap_size_t nbyte,
+                                  ap_ssize_t *bytes_read);
+#endif
+
 /* Notes:
  *  On reading EOF, EOF will set in the flags and no further Input will
  * be done.
@@ -155,6 +163,15 @@
     else
 	fb->outbase = NULL;
 
+#ifdef APACHE_XLATE
+    fb->biol.bwrite = ap_bwrite_core;
+    fb->biol.bread = ap_bread_core;
+    fb->xbuf = NULL;
+    fb->xbufsize = 0;
+    fb->write_xlate = NULL;
+    fb->read_xlate = NULL;
+#endif /*APACHE_XLATE*/
+
     fb->inptr = fb->inbase;
 
     fb->incnt = 0;
@@ -171,6 +188,12 @@
 {
     BUFF *fb = v;
 
+#ifdef APACHE_XLATE
+    if (fb->xbuf) {
+        free(fb->xbuf);
+        fb->xbuf = NULL;
+    }
+#endif
     return iol_close(fb->iol);
 }
 
@@ -197,6 +220,28 @@
 	    /* XXX: should remove B_WR now... */
 	}
 	return iol_setopt(fb->iol, AP_IOL_TIMEOUT, optval);
+
+#ifdef APACHE_XLATE
+    case BO_WXLATE:
+        fb->write_xlate = (ap_xlate_t *)*(const ap_xlate_t **)optval;
+        if (fb->write_xlate) {
+            fb->biol.bwrite = ap_bwrite_xlate;
+        }
+        else {
+            fb->biol.bwrite = ap_bwrite_core;
+        }
+        return APR_SUCCESS;
+        
+    case BO_RXLATE:
+        fb->read_xlate = (ap_xlate_t *)*(const ap_xlate_t **)optval;
+        if (fb->read_xlate) {
+            fb->biol.bread = ap_bread_xlate;
+        }
+        else {
+            fb->biol.bread = ap_bread_core;
+        }
+        return APR_SUCCESS;
+#endif /*APACHE_XLATE*/
     }
     fb->berrno = APR_EINVAL;
     return APR_EINVAL;
@@ -216,6 +261,16 @@
 
     case BO_TIMEOUT:
 	return iol_getopt(fb->iol, AP_IOL_TIMEOUT, optval);
+        
+#ifdef APACHE_XLATE
+    case BO_WXLATE:
+        *(ap_xlate_t **)optval = fb->write_xlate;
+        return APR_SUCCESS;
+        
+    case BO_RXLATE:
+        *(ap_xlate_t **)optval = fb->read_xlate;
+        return APR_SUCCESS;
+#endif /*APACHE_XLATE*/
     }
     fb->berrno = APR_EINVAL;
     return APR_EINVAL;
@@ -247,6 +302,9 @@
     int i;
     unsigned char *strp;
     int chunk_size;
+#ifdef CHARSET_EBCDIC
+    ap_size_t inbytes_left, outbytes_left;
+#endif
 
     chunk_size = fb->outcnt - fb->outchunk - CHUNK_HEADER_SIZE + extra;
     if (chunk_size == 0) {
@@ -277,9 +335,20 @@
         *strp++ = ' ';
         ++i;
     }
+    /* CRLF intentionally left hardcoded in ascii on ebcdic boxes */
     *strp++ = '\015';
     *strp = '\012';
 
+#ifdef CHARSET_EBCDIC
+    /* Convert printable hex chunk size and padding from ebcdic->ascii,
+     * but leave CRLF in ascii
+     */
+    inbytes_left = outbytes_left = CHUNK_HEADER_SIZE - 2;
+    ap_xlate_conv_buffer(ap_hdrs_to_ascii,
+                         &fb->outbase[fb->outchunk], &inbytes_left,
+                         &fb->outbase[fb->outchunk], &outbytes_left);
+#endif /*CHARSET_EBCDIC*/
+
     if (extra == 0) {
 	/* tack on the trailing CRLF, we've reserved room for this */
 	fb->outbase[fb->outcnt++] = '\015';
@@ -339,12 +408,32 @@
 }
 
 
+#ifdef APACHE_XLATE
+static ap_status_t ap_bread_xlate(BUFF *fb, void *buf, ap_size_t nbyte,
+                                  ap_ssize_t *bytes_read)
+{
+    ap_status_t rv;
+    ap_size_t inbytes_left, outbytes_left;
+    
+    rv = ap_bread_core(fb, fb->xbuf, nbyte, bytes_read);
+    if (rv == APR_SUCCESS && *bytes_read) {
+        inbytes_left = outbytes_left = *bytes_read;
+        rv = ap_xlate_conv_buffer(fb->read_xlate, fb->inptr, &inbytes_left,
+                                  buf, &outbytes_left);
+        ap_assert(!rv && !inbytes_left && !outbytes_left);
+    }
+
+    return rv;
+}
+#endif /* APACHE_XLATE */
+
+
 /*
  * Read up to nbyte bytes into buf.
  * If fewer than byte bytes are currently available, then return those.
  */
-API_EXPORT(ap_status_t) ap_bread(BUFF *fb, void *buf, ap_size_t nbyte,
-                                 ap_ssize_t *bytes_read)
+API_EXPORT(ap_status_t) ap_bread_core(BUFF *fb, void *buf, ap_size_t nbyte,
+                                      ap_ssize_t *bytes_read)
 {
     int nrd;
     ap_ssize_t i;
@@ -370,7 +459,7 @@
             *bytes_read = i;
 	    return APR_SUCCESS;
 	}
-	return read_with_errors(fb, buf, nbyte, bytes_read);
+        return read_with_errors(fb, buf, nbyte, bytes_read);
     }
 
     nrd = fb->incnt;
@@ -478,6 +567,15 @@
 	}
 
 	ch = fb->inptr[i++];
+#ifdef APACHE_XLATE
+        if (fb->read_xlate)
+            ch = ap_xlate_conv_byte(fb->read_xlate, (unsigned char)ch);
+
+        /* AS/400 problem not handled by this code...
+         * It's possible that a cgi program may return 0x15 as LF and
+         * since we don't know how it's built, we need to look for both.
+         */
+#endif
 	if (ch == LF) {	/* got LF */
 	    if (ct == 0)
 		buff[ct++] = '\n';
@@ -708,7 +806,9 @@
 	    return APR_SUCCESS;
 	}
 	/* we've finished the overcommit so we end off the previous
-	   chunk, begin a new one, and shift buf */
+	   chunk, begin a new one, and shift buf
+
+           CRLF is intentionally left hardcoded in ascii on ebcdic boxes */
 	fb->outbase[0] = '\015';
 	fb->outbase[1] = '\012';
 	fb->outcnt = 2;
@@ -785,7 +885,40 @@
     return APR_SUCCESS;
 }
 
+#ifdef APACHE_XLATE
+static ap_status_t ap_bwrite_xlate(BUFF *fb, const void *buf, ap_size_t nbyte,
+                                  ap_ssize_t *bytes_written)
+{
+    ap_size_t inbytes_left, outbytes_left;
+    ap_status_t rv;
+    
+    if (fb->flags & (B_WRERR | B_EOUT)) {
+        *bytes_written = 0;
+	return fb->saved_errno;
+    }
+    if (nbyte == 0) {
+        *bytes_written = 0;
+	return APR_SUCCESS;
+    }
 
+    if (nbyte > fb->xbufsize) {
+        if (fb->xbuf != NULL) {
+            free(fb->xbuf);
+        }
+        fb->xbufsize = (nbyte + HUGE_STRING_LEN + 1023) & ~1023;
+        fb->xbuf = (char *)malloc(fb->xbufsize);
+        ap_assert(fb->xbuf);
+    }
+    inbytes_left = outbytes_left = nbyte;
+    rv = ap_xlate_conv_buffer(fb->write_xlate, buf, &inbytes_left,
+                              fb->xbuf ? fb->xbuf : (void *)buf, &outbytes_left);
+    /* we still only handle SBCS conversions */
+    ap_assert(!rv && !inbytes_left && !outbytes_left);
+
+    return ap_bwrite_core(fb, fb->xbuf, nbyte, bytes_written);
+}
+#endif /* APACHE_XLATE */
+
 /*
  * Write nbyte bytes.
  * Only returns fewer than nbyte if an error ocurred.
@@ -793,7 +926,7 @@
  * It is worth noting that if an error occurs, the buffer is in an unknown
  * state.
  */
-API_EXPORT(ap_status_t) ap_bwrite(BUFF *fb, const void *buf, ap_size_t nbyte,
+API_EXPORT(ap_status_t) ap_bwrite_core(BUFF *fb, const void *buf, ap_size_t nbyte,
                                   ap_ssize_t *bytes_written)
 {
     int amt;
@@ -899,6 +1032,13 @@
     ap_kill_cleanup(fb->pool, fb, bcleanup);
     rc2 = iol_close(fb->iol);
 
+#ifdef APACHE_XLATE
+    if (fb->xbuf) {
+        free(fb->xbuf);
+        fb->xbuf = NULL;
+    }
+#endif
+
     fb->inptr = fb->inbase;
     fb->incnt = 0;
     fb->outcnt = 0;
@@ -979,6 +1119,20 @@
     struct bprintf_data *b = (struct bprintf_data *)vbuff;
     BUFF *fb = b->fb;
 
+#ifdef APACHE_XLATE
+    ap_size_t inbytes_left, outbytes_left;
+    ap_status_t rv;
+    
+    /* Characters were pushed into the buffer without conversion. Do it now */
+    if (fb->write_xlate) {
+        inbytes_left = outbytes_left =
+            b->vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
+        rv = ap_xlate_conv_buffer(fb->write_xlate, &fb->outbase[fb->outcnt],
+                                  &inbytes_left, &fb->outbase[fb->outcnt],
+                                  &outbytes_left);
+        ap_assert(!rv && !inbytes_left && !outbytes_left);
+    }
+#endif /*APACHE_XLATE*/
     fb->outcnt += b->vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
     if (fb->outcnt == fb->bufsiz) {
 	if (ap_bflush(fb) != APR_SUCCESS) {
@@ -1008,6 +1162,20 @@
     res = ap_vformatter(bprintf_flush, &b.vbuff, fmt, ap);
     va_end(ap);
     if (res != -1) {
+#ifdef APACHE_XLATE
+	/* Characters were pushed into the buffer without conversion. Do it now */
+	if (fb->write_xlate) {
+            ap_size_t inbytes_left, outbytes_left;
+            ap_status_t rv;
+
+            inbytes_left = outbytes_left =
+                b.vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
+	    rv = ap_xlate_conv_buffer(fb->write_xlate, &fb->outbase[fb->outcnt],
+                                      &inbytes_left, &fb->outbase[fb->outcnt],
+                                      &outbytes_left);
+            ap_assert(!rv && !inbytes_left && !outbytes_left);
+        }
+#endif /*APACHE_XLATE*/
 	fb->outcnt += b.vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
     }
     return res;
@@ -1028,6 +1196,20 @@
     b.fb = fb;
     res = ap_vformatter(bprintf_flush, &b.vbuff, fmt, ap);
     if (res != -1) {
+#ifdef APACHE_XLATE
+	/* Characters were pushed into the buffer without conversion. Do it now */
+	if (fb->write_xlate) {
+            ap_size_t inbytes_left, outbytes_left;
+            ap_status_t rv;
+
+            inbytes_left = outbytes_left =
+                b.vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
+            rv = ap_xlate_conv_buffer(fb->write_xlate, &fb->outbase[fb->outcnt],
+                                      &inbytes_left, &fb->outbase[fb->outcnt],
+                                      &outbytes_left);
+            ap_assert(!rv && !inbytes_left && !outbytes_left);
+        }
+#endif /*APACHE_XLATE*/
 	fb->outcnt += b.vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
     }
     return res;


-- 
Jeff Trawick | trawick@ibm.net | PGP public key at web site:
     http://www.geocities.com/SiliconValley/Park/9289/
          Born in Roswell... married an alien...

Mime
View raw message