httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Davi Arnaut <d...@haxent.com.br>
Subject [patch 09/16] simplify array and table serialization
Date Wed, 20 Sep 2006 02:34:02 GMT
Simplify the array and table serialization code, separating it from
the underlying I/O operations.

Index: modules/cache/cache_util.c
===================================================================
--- modules/cache/cache_util.c.orig
+++ modules/cache/cache_util.c
@@ -25,6 +25,126 @@
 
 extern module AP_MODULE_DECLARE_DATA cache_module;
 
+#define CLSP        ": "
+#define ARRAY_SEP   ','
+
+static APR_INLINE void *ap_mempcpy(void *dest, const void *src, size_t n)
+{
+    return memcpy(dest, src, n) + n;
+}
+
+/* XXX this function will change later */
+char *table_serialize(apr_pool_t *p, apr_table_t *table, apr_size_t *len)
+{
+    char *str, *pstr;
+    apr_size_t *tlen;
+    const apr_array_header_t *header = apr_table_elts(table);
+    apr_table_entry_t *entry = (apr_table_entry_t *) header->elts;
+    int i, n, nelts = header->nelts;
+
+    tlen = apr_palloc(p, sizeof(int) * nelts * 2);
+
+    *len = 0;
+
+    for (i = 0, n = 0; i < nelts; i++) {
+        *len += tlen[n++] = strlen(entry[i].key);
+        *len += tlen[n++] = strlen(entry[i].val);
+    }
+
+    /* key ': ' val '\r\n' */
+    *len += nelts * 4;
+
+    pstr = str = apr_palloc(p, *len + 1);
+
+    for (i = 0, n = 0; i < nelts; i++) {
+        pstr = ap_mempcpy(pstr, entry[i].key, tlen[n++]);
+        pstr = ap_mempcpy(pstr, CLSP, sizeof(CLSP) - 1);
+        pstr = ap_mempcpy(pstr, entry[i].val, tlen[n++]);
+        pstr = ap_mempcpy(pstr, CRLF, sizeof(CRLF) - 1);
+    }
+
+    *pstr = '\0';
+
+    return str;
+}
+
+/* XXX this function will change later */
+char *array_serialize(apr_pool_t *p, apr_array_header_t *array, apr_size_t *len)
+{
+    char *str;
+
+    str = apr_array_pstrcat(p, array, ARRAY_SEP);
+
+    *len = strlen(str);
+
+    return str;
+}
+
+char *ap_cache_strtok(char *str, apr_size_t *slen, const char *token,
+                      apr_size_t tlen)
+{
+    char *pstr = str;
+    apr_size_t i, len = *slen - tlen;
+
+    for (i = 0; i <= len; i++, pstr++) {
+        if (!memcmp(pstr, token, tlen)) {
+            break;
+        }
+    }
+
+    if (i > len)
+        return NULL;
+
+    *pstr = '\0';
+
+    *slen -= i + tlen;
+
+    return pstr + tlen;
+}
+
+/* XXX this function will change later */
+apr_size_t table_unserialize(apr_table_t *table, char *str, apr_size_t len)
+{
+    char *key, *val, *pstr = str;
+
+    do {
+        key = pstr;
+
+        pstr = ap_cache_strtok(pstr, &len, CLSP, sizeof CLSP - 1);
+
+        if (pstr == NULL)
+            break;
+
+        val = pstr;
+
+        pstr = ap_cache_strtok(pstr, &len, CRLF, sizeof CRLF - 1);
+
+        if (pstr == NULL)
+            break;
+
+        apr_table_add(table, key, val);
+    } while (len);
+
+    return len;
+}
+
+/* XXX this function will change later */
+void array_unserialize(apr_array_header_t *array, char *str)
+{
+    char *entry, *pstr = str;
+
+    do {
+        APR_ARRAY_PUSH(array, char *) = entry = pstr;
+
+        pstr = strchr(pstr, ARRAY_SEP);
+
+        if (pstr == NULL)
+            break;
+
+        *pstr++ = '\0';
+    } while (1);
+}
+
 /* Determine if "url" matches the hostname, scheme and port and path
  * in "filter". All but the path comparisons are case-insensitive.
  */
Index: modules/cache/mod_cache.h
===================================================================
--- modules/cache/mod_cache.h.orig
+++ modules/cache/mod_cache.h
@@ -252,6 +252,13 @@
 
 
 /* cache_util.c */
+char *ap_cache_strtok(char *str, apr_size_t *slen, const char *token,
+                      apr_size_t tlen);
+char *table_serialize(apr_pool_t *p, apr_table_t *table, apr_size_t *len);
+apr_size_t table_unserialize(apr_table_t *table, char *str, apr_size_t len);
+char *array_serialize(apr_pool_t *p, apr_array_header_t *array, apr_size_t *len);
+void array_unserialize(apr_array_header_t *array, char *str);
+
 /* do a HTTP/1.1 age calculation */
 CACHE_DECLARE(apr_time_t) ap_cache_current_age(cache_info *info, const apr_time_t age_value,
                                                apr_time_t now);
Index: modules/cache/mod_disk_cache.c
===================================================================
--- modules/cache/mod_disk_cache.c.orig
+++ modules/cache/mod_disk_cache.c
@@ -45,10 +45,10 @@
  * Format #2:
  *   disk_cache_info_t (first sizeof(apr_uint32_t) bytes is the format)
  *   entity name (dobj->name) [length is in disk_cache_info_t->name_len]
+ *   size of headers_out (delimited by CRLF)
  *   r->headers_out (delimited by CRLF)
- *   CRLF
+ *   size of headers_in (delimited by CRLF)
  *   r->headers_in (delimited by CRLF)
- *   CRLF
  */
 
 module AP_MODULE_DECLARE_DATA disk_cache_module;
@@ -59,8 +59,7 @@
 static apr_status_t store_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b);
 static apr_status_t recall_headers(cache_handle_t *h, request_rec *r);
 static apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb);
-static apr_status_t read_array(request_rec *r, apr_array_header_t* arr,
-                               apr_file_t *file);
+static apr_status_t read_array(apr_array_header_t* arr, apr_file_t *file);
 
 /*
  * Local static functions
@@ -457,7 +456,7 @@
         }
 
         varray = apr_array_make(r->pool, 5, sizeof(char*));
-        rc = read_array(r, varray, dobj->hfd);
+        rc = read_array(varray, dobj->hfd);
         if (rc != APR_SUCCESS) {
             ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server,
                          "disk_cache: Cannot parse vary header file: %s",
@@ -582,149 +581,127 @@
     return OK;
 }
 
-static apr_status_t read_array(request_rec *r, apr_array_header_t* arr,
-                               apr_file_t *file)
+/* XXX this is a temporary function, it will be removed later */
+static apr_status_t read_array(apr_array_header_t* array, apr_file_t *file)
 {
-    char w[MAX_STRING_LEN];
-    int p;
     apr_status_t rv;
+    apr_size_t nbytes;
+    apr_finfo_t finfo;
+    char *buffer, *end;
 
-    while (1) {
-        rv = apr_file_gets(w, MAX_STRING_LEN - 1, file);
-        if (rv != APR_SUCCESS) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                          "Premature end of vary array.");
-            return rv;
-        }
+    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file);
 
-        p = strlen(w);
-        if (p > 0 && w[p - 1] == '\n') {
-            if (p > 1 && w[p - 2] == CR) {
-                w[p - 2] = '\0';
-            }
-            else {
-                w[p - 1] = '\0';
-            }
-        }
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
 
-        /* If we've finished reading the array, break out of the loop. */
-        if (w[0] == '\0') {
-            break;
-        }
+    nbytes = finfo.size;
 
-       *((const char **) apr_array_push(arr)) = apr_pstrdup(r->pool, w);
+    buffer = apr_palloc(array->pool, nbytes);
+
+    rv = apr_file_read(file, buffer, &nbytes);
+
+    if (rv != APR_SUCCESS) {
+        return rv;
     }
 
+    end = memchr(buffer, CR, nbytes);
+
+    if (end == NULL) {
+        return APR_EGENERAL;
+    }
+
+    *end = '\0';
+
+    array_unserialize(array, buffer);
+
     return APR_SUCCESS;
 }
 
-static apr_status_t store_array(apr_file_t *fd, apr_array_header_t* arr)
+/* XXX this is a temporary function, it will be removed later */
+static apr_status_t store_array(apr_pool_t *p, apr_file_t *fd,
+                                apr_array_header_t* array)
 {
-    int i;
+    char *str;
+    apr_size_t len;
+
+    str = array_serialize(p, array, &len);
+
+    if (apr_file_printf(fd, "%s" CRLF, str) < 0)
+        return APR_EGENERAL;
+    else
+        return APR_SUCCESS;
+}
+
+/* XXX this is a temporary function, it will be removed later */
+static apr_status_t read_table(apr_pool_t *p, apr_table_t *table, apr_file_t *fd)
+{
+    char *end, *buf;
     apr_status_t rv;
-    struct iovec iov[2];
-    apr_size_t amt;
-    const char **elts;
+    apr_size_t nbytes;
+    apr_off_t offset = 0;
+    apr_size_t bytes_read = 0;
+    char buffer[HUGE_STRING_LEN];
 
-    elts = (const char **) arr->elts;
+    buf = buffer;
+    nbytes = sizeof buffer;
 
-    for (i = 0; i < arr->nelts; i++) {
-        iov[0].iov_base = (char*) elts[i];
-        iov[0].iov_len = strlen(elts[i]);
-        iov[1].iov_base = CRLF;
-        iov[1].iov_len = sizeof(CRLF) - 1;
+    rv = apr_file_seek(fd, APR_CUR, &offset);
 
-        rv = apr_file_writev(fd, (const struct iovec *) &iov, 2,
-                             &amt);
-        if (rv != APR_SUCCESS) {
-            return rv;
-        }
+    if (rv != APR_SUCCESS) {
+        return rv;
     }
 
-    iov[0].iov_base = CRLF;
-    iov[0].iov_len = sizeof(CRLF) - 1;
+    /* read the table length */
+    rv = apr_file_read(fd, buf, &nbytes);
 
-    return apr_file_writev(fd, (const struct iovec *) &iov, 1,
-                         &amt);
-}
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
 
-static apr_status_t read_table(cache_handle_t *handle, request_rec *r,
-                               apr_table_t *table, apr_file_t *file)
-{
-    char w[MAX_STRING_LEN];
-    char *l;
-    int p;
-    apr_status_t rv;
+    end = ap_cache_strtok(buf, &nbytes, CRLF, sizeof CRLF - 1);
 
-    while (1) {
+    if (end == NULL) {
+        return APR_EGENERAL;
+    }
 
-        /* ### What about APR_EOF? */
-        rv = apr_file_gets(w, MAX_STRING_LEN - 1, file);
-        if (rv != APR_SUCCESS) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                          "Premature end of cache headers.");
-            return rv;
-        }
+    offset += end - buf;
 
-        /* Delete terminal (CR?)LF */
+    /* set the offset past the table size */
+    rv = apr_file_seek(fd, APR_SET, &offset);
 
-        p = strlen(w);
-        /* Indeed, the host's '\n':
-           '\012' for UNIX; '\015' for MacOS; '\025' for OS/390
-           -- whatever the script generates.
-        */
-        if (p > 0 && w[p - 1] == '\n') {
-            if (p > 1 && w[p - 2] == CR) {
-                w[p - 2] = '\0';
-            }
-            else {
-                w[p - 1] = '\0';
-            }
-        }
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
 
-        /* If we've finished reading the headers, break out of the loop. */
-        if (w[0] == '\0') {
-            break;
-        }
+    rv = apr_strtoff(&offset, buf, &end, 0);
 
-#if APR_CHARSET_EBCDIC
-        /* Chances are that we received an ASCII header text instead of
-         * the expected EBCDIC header lines. Try to auto-detect:
-         */
-        if (!(l = strchr(w, ':'))) {
-            int maybeASCII = 0, maybeEBCDIC = 0;
-            unsigned char *cp, native;
-            apr_size_t inbytes_left, outbytes_left;
-
-            for (cp = w; *cp != '\0'; ++cp) {
-                native = apr_xlate_conv_byte(ap_hdrs_from_ascii, *cp);
-                if (apr_isprint(*cp) && !apr_isprint(native))
-                    ++maybeEBCDIC;
-                if (!apr_isprint(*cp) && apr_isprint(native))
-                    ++maybeASCII;
-            }
-            if (maybeASCII > maybeEBCDIC) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                             "CGI Interface Error: Script headers apparently ASCII: (CGI
= %s)",
-                             r->filename);
-                inbytes_left = outbytes_left = cp - w;
-                apr_xlate_conv_buffer(ap_hdrs_from_ascii,
-                                      w, &inbytes_left, w, &outbytes_left);
-            }
-        }
-#endif /*APR_CHARSET_EBCDIC*/
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
 
-        /* if we see a bogus header don't ignore it. Shout and scream */
-        if (!(l = strchr(w, ':'))) {
-            return APR_EGENERAL;
-        }
+    /* let's read and parse the table */
+    nbytes = (apr_size_t) offset;
 
-        *l++ = '\0';
-        while (*l && apr_isspace(*l)) {
-            ++l;
-        }
+    buf = buffer;
+
+    if (nbytes > sizeof buffer) {
+        buf = apr_palloc(p, nbytes);
+    }
+
+    rv = apr_file_read_full(fd, buf, nbytes, &bytes_read);
 
-        apr_table_add(table, w, l);
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
+    else if (nbytes != bytes_read) {
+        return APR_EGENERAL;
+    }
+
+    nbytes = table_unserialize(table, buf, bytes_read);
+
+    if (nbytes) {
+        return APR_EGENERAL;
     }
 
     return APR_SUCCESS;
@@ -751,8 +728,8 @@
     h->resp_hdrs = apr_table_make(r->pool, 20);
 
     /* Call routine to read the header lines/status line */
-    read_table(h, r, h->resp_hdrs, dobj->hfd);
-    read_table(h, r, h->req_hdrs, dobj->hfd);
+    read_table(r->pool, h->resp_hdrs, dobj->hfd);
+    read_table(r->pool, h->req_hdrs, dobj->hfd);
 
     apr_file_close(dobj->hfd);
 
@@ -774,38 +751,25 @@
     return APR_SUCCESS;
 }
 
-static apr_status_t store_table(apr_file_t *fd, apr_table_t *table)
+static apr_status_t store_table(apr_pool_t *p, apr_file_t *fd, apr_table_t *table)
 {
-    int i;
+    char *pstr;
+    apr_size_t len;
     apr_status_t rv;
-    struct iovec iov[4];
-    apr_size_t amt;
-    apr_table_entry_t *elts;
 
-    elts = (apr_table_entry_t *) apr_table_elts(table)->elts;
-    for (i = 0; i < apr_table_elts(table)->nelts; ++i) {
-        if (elts[i].key != NULL) {
-            iov[0].iov_base = elts[i].key;
-            iov[0].iov_len = strlen(elts[i].key);
-            iov[1].iov_base = ": ";
-            iov[1].iov_len = sizeof(": ") - 1;
-            iov[2].iov_base = elts[i].val;
-            iov[2].iov_len = strlen(elts[i].val);
-            iov[3].iov_base = CRLF;
-            iov[3].iov_len = sizeof(CRLF) - 1;
+    pstr = table_serialize(p, table, &len);
 
-            rv = apr_file_writev(fd, (const struct iovec *) &iov, 4,
-                                 &amt);
-            if (rv != APR_SUCCESS) {
-                return rv;
-            }
-        }
+    if (pstr == NULL) {
+        return APR_ENOMEM;
     }
-    iov[0].iov_base = CRLF;
-    iov[0].iov_len = sizeof(CRLF) - 1;
-    rv = apr_file_writev(fd, (const struct iovec *) &iov, 1,
-                         &amt);
-    return rv;
+
+    rv = apr_file_printf(fd, "%" APR_SIZE_T_FMT CRLF, len);
+
+    if (rv < 0) {
+        return APR_EGENERAL;
+    }
+
+    return apr_file_write_full(fd, pstr, len, NULL);
 }
 
 static apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info *info)
@@ -848,7 +812,7 @@
             varray = apr_array_make(r->pool, 6, sizeof(char*));
             tokens_to_array(r->pool, tmp, varray);
 
-            store_array(dobj->tfd, varray);
+            store_array(r->pool, dobj->tfd, varray);
 
             apr_file_close(dobj->tfd);
 
@@ -916,7 +880,7 @@
 
         headers_out = apr_table_overlay(r->pool, headers_out,
                                         r->err_headers_out);
-        rv = store_table(dobj->hfd, headers_out);
+        rv = store_table(r->pool, dobj->hfd, headers_out);
         if (rv != APR_SUCCESS) {
             return rv;
         }
@@ -929,7 +893,7 @@
 
         headers_in = ap_cache_cacheable_hdrs_out(r->pool, r->headers_in,
                                                  r->server);
-        rv = store_table(dobj->hfd, headers_in);
+        rv = store_table(r->pool, dobj->hfd, headers_in);
         if (rv != APR_SUCCESS) {
             return rv;
         }

--

Mime
View raw message