You are viewing a plain text version of this content. The canonical link for it is here.
Posted to general@commons.apache.org by je...@apache.org on 2003/10/30 08:00:56 UTC

svn commit: rev 58 - in commons/serf/branches/gen2: . buckets test

Author: jerenkrantz
Date: Wed Oct 29 23:00:55 2003
New Revision: 58

Added:
   commons/serf/branches/gen2/buckets/aggregate_buckets.c
   commons/serf/branches/gen2/buckets/request_buckets.c
   commons/serf/branches/gen2/test/
   commons/serf/branches/gen2/test/serf_get.c
      - copied, changed from rev 57, commons/serf/trunk/test/serf_get.c
Modified:
   commons/serf/branches/gen2/buckets/buckets.c
   commons/serf/branches/gen2/serf.h
   commons/serf/branches/gen2/serf_bucket_types.h
Log:
Take a pass at the API and fleshing some things out.  Implemented a few
files just to see if Greg and I are on the same page.  We'll find out...

* test/serf_get.c (copied): Copied from trunk.  This is a simple test
  app that has some broken code for the new API.
* bucket/buckets.c (modified): Add a pool to serf_bucket_alloc_t,
  define a primitive serf_metadata_t with just a hash, add set/get_metadata
  defaults, implement the bucket_mem_alloc and bucket_mem_free calls.
* bucket/aggregate_buckets.c (new file): Add 'initial' aggregate buckets.
* bucket/request_buckets.c (new file): Add 'initial' request buckets.
* serf.h: Add serf_bucket_allocator_create() public declaration - notice
  that I had it grow a pool.  *shrug*  See forthcoming STATUS commit...
* serf_bucket_types.h (SERF_REQUEST_HEADERS): Add 'public' metadata kind for
  request bucket to set the HTTP headers.


Added: commons/serf/branches/gen2/buckets/aggregate_buckets.c
==============================================================================
--- (empty file)
+++ commons/serf/branches/gen2/buckets/aggregate_buckets.c	Wed Oct 29 23:00:55 2003
@@ -0,0 +1,187 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ */
+
+#include <apr_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+/* Should be an APR_RING? */
+typedef struct bucket_list {
+    serf_bucket_t *bucket;
+    struct bucket_list *next;
+} bucket_list;
+
+typedef struct serf_aggregate_context_t {
+    bucket_list *list;
+} serf_aggregate_context_t;
+
+SERF_DECLARE(serf_bucket_t *) serf_bucket_aggregate_create(
+    serf_bucket_alloc_t *allocator)
+{
+    serf_aggregate_context_t *agg_context;
+
+    serf_bucket_mem_alloc(allocator, sizeof(*agg_context));
+
+    /* Theoretically, we *could* store this in the metadata of our bucket,
+     * but that'd be ridiculously slow.
+     */
+    agg_context->list = NULL;
+
+    return serf_bucket_create(serf_bucket_type_aggregate, allocator,
+                              agg_context);
+}
+
+SERF_DECLARE(void) serf_bucket_aggregate_become(serf_bucket_t *bucket)
+{
+    /* Create a new bucket and swap their internal pointers? */
+}
+
+
+SERF_DECLARE(void) serf_bucket_aggregate_prepend(
+    serf_bucket_t *aggregate_bucket,
+    serf_bucket_t *prepend_bucket)
+{
+    serf_aggregate_context_t *agg_context;
+    bucket_list *new_bucket;
+
+    agg_context = (serf_aggregate_context_t*)aggregate_bucket->data;
+    new_bucket = serf_bucket_mem_alloc(aggregate_bucket->allocator,
+                                       sizeof(*bucket_list));
+
+    new_bucket->bucket = prepend_bucket;
+    new_bucket->next = agg_context->list;
+    agg_context->list = new_bucket;
+}
+
+SERF_DECLARE(void) serf_bucket_aggregate_append(
+    serf_bucket_t *aggregate_bucket,
+    serf_bucket_t *prepend_bucket)
+{
+    serf_aggregate_context_t *agg_context;
+    bucket_list *new_bucket;
+
+    agg_context = (serf_aggregate_context_t*)aggregate_bucket->data;
+    new_bucket = serf_bucket_mem_alloc(aggregate_bucket->allocator,
+                                       sizeof(*bucket_list));
+
+    /* If we use APR_RING, this is trivial.  So, wait. 
+    new_bucket->bucket = prepend_bucket;
+    new_bucket->next = agg_context->list;
+    agg_context->list = new_bucket;
+    */
+}
+
+static apr_status_t serf_aggregate_read(serf_bucket_t *bucket,
+                                        apr_size_t requested,
+                                        const char **data, apr_size_t *len)
+{
+    apr_status_t status;
+    serf_aggregate_context_t *agg_context;
+
+    agg_context = (serf_aggregate_context_t*)aggregate_bucket->data;
+    if (!agg_context->list) {
+        *len = 0;
+        return APR_SUCCESS;
+    }
+
+    status = serf_bucket_read(agg_context->list->bucket, requested, data, len);
+
+    /* Somehow, we need to know whether we're exhausted! */
+    if (!status && *len == 0) {
+        agg_context->list = agg_context->list->next;
+        /* Avoid recursive call here.  Too lazy now.  */
+        return serf_aggregate_read(bucket, request, data, len);
+    }
+
+    return status;
+}
+
+static apr_status_t serf_aggregate_readline(serf_bucket_t *bucket,
+                                            int acceptable, int *found,
+                                            const char **data, apr_size_t *len)
+{
+    /* Follow pattern from serf_aggregate_read. */
+    return APR_ENOTIMPL;
+}
+
+static apr_status_t serf_aggregate_peek(serf_bucket_t *bucket,
+                                        const char **data,
+                                        apr_size_t *len)
+{
+    /* Follow pattern from serf_aggregate_read. */
+    return APR_ENOTIMPL;
+}
+
+static serf_bucket_t * serf_aggregate_read_bucket(serf_bucket_t *bucket,
+                                                  serf_bucket_type_t *type)
+{
+    apr_status_t status;
+    serf_aggregate_context_t *agg_context;
+
+    agg_context = (serf_aggregate_context_t*)aggregate_bucket->data;
+    if (!agg_context->list) {
+        return NULL;
+    }
+
+    /* Call read_bucket on first one in our list. */
+    return serf_bucket_read_bucket(agg_context->list->bucket, type);
+}
+
+SERF_DECLARE_DATA serf_bucket_type_t serf_bucket_type_aggregate {
+    "AGGREGATE",
+    serf_aggregate_read,
+    serf_aggregate_readline,
+    serf_aggregate_peek,
+    serf_aggregate_read_bucket,
+    NULL, /* set_metadata */
+    NULL, /* get_metadata */
+    serf_default_destroy,
+};

Modified: commons/serf/branches/gen2/buckets/buckets.c
==============================================================================
--- commons/serf/branches/gen2/buckets/buckets.c	(original)
+++ commons/serf/branches/gen2/buckets/buckets.c	Wed Oct 29 23:00:55 2003
@@ -55,8 +55,12 @@
 
 struct serf_bucket_alloc_t {
     apr_allocator_t *allocator;
+    apr_pool_t *pool;
 };
 
+struct serf_metadata_t {
+    apr_hash_t *hash;
+};
 
 SERF_DECLARE(serf_bucket_t *) serf_bucket_create(
     serf_bucket_type_t *type,
@@ -67,7 +71,8 @@
 
     bkt->type = type;
     bkt->data = data;
-    bkt->metadata = NULL;
+    bkt->metadata = serf_bucket_mem_alloc(allocator, sizeof(*bkt->metadata));
+    bkt->metadata->hash = NULL;
     bkt->allocator = allocator;
 
     return bkt;
@@ -78,7 +83,27 @@
                                                      const char *md_name,
                                                      const void *md_value)
 {
-    return APR_ENOTIMPL;
+    apr_hash_t *md_hash;
+
+    md_hash = NULL;
+
+    if (!bucket->metadata->hash) {
+        bucket->metadata->hash = apr_hash_make(bucket->allocator->pool);
+    }
+    else {
+        md_hash = apr_hash_get(bucket->metadata->hash, md_type,
+                               APR_HASH_KEY_STRING);
+    }
+
+    if (!md_hash) {
+        md_hash = apr_hash_make(bucket->allocator->pool);
+        apr_hash_set(bucket->metadata->hash, md_type, APR_HASH_KEY_STRING,
+                     md_hash);
+    }
+
+    apr_hash_set(md_hash, md_name, APR_HASH_KEY_STRING, md_value);
+
+    return APR_SUCCESS;
 }
 
 
@@ -87,7 +112,21 @@
                                                      const char *md_name,
                                                      const void **md_value)
 {
-    return APR_ENOTIMPL;
+    /* Initialize return value to not being found. */
+    *md_value = NULL;
+
+    if (bucket->metadata->hash) {
+        apr_hash_t *md_hash;
+
+        md_hash = apr_hash_get(bucket->metadata->hash, md_type,
+                               APR_HASH_KEY_STRING);
+
+        if (md_hash) {
+            *md_value = apr_hash_get(md_hash, md_name, APR_HASH_KEY_STRING);
+        }
+    }
+
+    return APR_SUCCESS;
 }
 
 SERF_DECLARE(serf_bucket_t *) serf_default_read_bucket(
@@ -99,6 +138,7 @@
 
 SERF_DECLARE(void) serf_default_destroy(serf_bucket_t *bucket)
 {
+    serf_bucket_mem_free(bucket->allocator, bucket->metadata);
     serf_bucket_mem_free(bucket->allocator, bucket);
 }
 
@@ -107,12 +147,12 @@
 
 
 SERF_DECLARE(serf_bucket_alloc_t *) serf_bucket_allocator_create(
-    apr_allocator_t *allocator)
+    apr_allocator_t *allocator, apr_pool_t *pool)
 {
     serf_bucket_alloc_t *a = apr_allocator_alloc(allocator, sizeof(*a));
 
     a->allocator = allocator;
-
+    a->pool = pool;
     /* ### more */
 
     return a;
@@ -121,6 +161,7 @@
 SERF_DECLARE(void) serf_bucket_allocator_destroy(
     serf_bucket_alloc_t *allocator)
 {
+    /* We don't (yet) own the pool passed in to our allocator_create. */
     apr_allocator_destroy(allocator->allocator);
 }
 
@@ -128,13 +169,12 @@
     serf_bucket_alloc_t *allocator,
     apr_size_t size)
 {
-    /* ### need real code */
-    return NULL;
+    return apr_allocator_alloc(allocator->allocator, size);
 }
 
 SERF_DECLARE(void) serf_bucket_mem_free(
     serf_bucket_alloc_t *allocator,
     void *block)
 {
-    /* ### need real code */
+    apr_allocator_free(allocator->allocator, block);
 }

Added: commons/serf/branches/gen2/buckets/request_buckets.c
==============================================================================
--- (empty file)
+++ commons/serf/branches/gen2/buckets/request_buckets.c	Wed Oct 29 23:00:55 2003
@@ -0,0 +1,169 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ */
+
+#include <apr_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+typedef enum serf_request_state_t {
+    UNREAD,
+    READING_STATUS,
+    READING_HEADERS,
+    READING_BODY,
+    EXHAUSTED
+} serf_request_state_t;
+
+typedef struct serf_request_context_t {
+    const char *method;
+    const char *uri;
+    serf_bucket_t *body;
+    serf_request_state_t state;
+} serf_request_context_t;
+
+SERF_DECLARE(serf_bucket_t *) serf_bucket_request_create(
+    const char *method,
+    const char *uri,
+    serf_bucket_t *body,
+    serf_bucket_alloc_t *allocator)
+{
+    serf_request_context_t *req_context;
+
+    serf_bucket_mem_alloc(allocator, sizeof(*req_context));
+
+    /* Theoretically, we *could* store this in the metadata of our bucket,
+     * but that'd be ridiculously slow.
+     */
+    req_context->method = method;
+    req_context->uri = uri;
+    req_context->body = body;
+    req_context->state = UNREAD;
+
+    return serf_bucket_create(serf_bucket_type_request, allocator, data);
+}
+
+static apr_status_t serf_request_read(serf_bucket_t *bucket,
+                                      apr_size_t requested,
+                                      const char **data, apr_size_t *len)
+{
+    serf_request_context_t *req_context;
+    serf_bucket_t *new_bucket;
+    const char *new_data;
+
+    req_context = (serf_request_context_t*)bucket->data;
+    new_bucket = NULL;
+
+    /* We'll store whatever we generate into a new bucket and update our
+     * state accordingly.
+     */
+    switch (req_context->state) {
+    case UNREAD:
+        /* Store method line. */
+        /* ARGH.  Allocator needs to be public? */
+        new_data = apr_pstrcat(bucket->allocator->pool,
+                               req_context->method, " ",
+                               req_context->uri, " HTTP/1.1", NULL);
+        /* heap, pool, whatever. */
+        new_bucket = serf_bucket_pool_create(bucket->allocator, new_data);
+        req_context->state = READ_STATUS;
+        break;
+    case READ_STATUS:
+        /* Store method line. */
+        req_context->state = READ_HEADERS;
+        break;
+    case READ_HEADERS:
+        /* Return all headers. */
+        req_context->state = READ_BODY;
+        break;
+    case READ_BODY:
+        /* Just read from the body at this point! */
+        req_context->state = READ_EXHAUSTED;
+        break;
+    case EXHAUSTED:
+        /* Hmm.  How did we get here? */
+        break;
+    }
+
+    if (!new_bucket) {
+        *len = 0;
+        return APR_SUCCESS;
+    }
+
+    /* Okay, so we created a bucket.  Pass the 'hard' stuff to that bucket. */
+    /* This better have the semantics we want in that bucket is pushed down. */
+    serf_bucket_aggregate_become(bucket);
+    serf_bucket_aggregate_prepend(bucket, new_bucket);
+    return serf_bucket_read(bucket, data, len);
+}
+
+static apr_status_t serf_request_readline(serf_bucket_t *bucket,
+                                          int acceptable, int *found,
+                                          const char **data, apr_size_t *len)
+{
+    return APR_ENOTIMPL;
+}
+
+static apr_status_t serf_request_peek(serf_bucket_t *bucket,
+                                      const char **data,
+                                      apr_size_t *len)
+{
+    return APR_ENOTIMPL;
+}
+
+SERF_DECLARE_DATA serf_bucket_type_t serf_bucket_type_request {
+    "REQUEST",
+    serf_request_read,
+    serf_request_readline,
+    serf_request_peek,
+    serf_default_read_bucket,
+    serf_default_set_metadata,
+    serf_default_get_metadata,
+    serf_default_destroy,
+};

Modified: commons/serf/branches/gen2/serf.h
==============================================================================
--- commons/serf/branches/gen2/serf.h	(original)
+++ commons/serf/branches/gen2/serf.h	Wed Oct 29 23:00:55 2003
@@ -58,6 +58,7 @@
 
 #include <apr.h>
 #include <apr_errno.h>
+#include <apr_allocator.h>
 #include <apr_pools.h>
 
 #include "serf_declare.h"
@@ -93,6 +94,13 @@
  */
 SERF_DECLARE(serf_context_t *) serf_context_create(apr_pool_t *pool);
 
+/**
+ * Create a new allocator for buckets from an APR allocator.
+ *
+ * All buckets are associated with a serf bucket allocator.
+ */
+SERF_DECLARE(serf_bucket_alloc_t *) serf_bucket_allocator_create(
+    apr_allocator_t *allocator, apr_pool_t *pool);
 
 /** @see serf_context_run should not block at all. */
 #define SERF_DURATION_NOBLOCK 0

Modified: commons/serf/branches/gen2/serf_bucket_types.h
==============================================================================
--- commons/serf/branches/gen2/serf_bucket_types.h	(original)
+++ commons/serf/branches/gen2/serf_bucket_types.h	Wed Oct 29 23:00:55 2003
@@ -81,6 +81,8 @@
     serf_bucket_t *body,
     serf_bucket_alloc_t *allocator);
 
+/* Metadata key for get/set_metadata */
+#define SERF_REQUEST_HEADERS "REQUESTHEADERS"
 
 /* ==================================================================== */
 

Copied: commons/serf/branches/gen2/test/serf_get.c (from rev 57, commons/serf/trunk/test/serf_get.c)
==============================================================================
--- commons/serf/trunk/test/serf_get.c	(original)
+++ commons/serf/branches/gen2/test/serf_get.c	Wed Oct 29 23:00:55 2003
@@ -270,18 +270,45 @@
     return APR_SUCCESS;
 }
 
+void closed_connection(serf_connection_t *conn,
+                       void *closed_baton,
+                       apr_status_t why,
+                       apr_pool_t *pool)
+{
+
+}
+
+serf_bucket_t* accept_response(serf_connection_t *conn,
+                               apr_socket_t *socket,
+                               void *acceptor_baton,
+                               apr_pool_t *respool,
+                               apr_pool_t *tmppool)
+{
+
+}
+
+apr_status_t handle_response(serf_bucket_t *response,
+                             void *handler_baton,
+                             apr_pool_t *pool)
+{
+
+}
+
 int main(int argc, const char **argv)
 {
     apr_status_t status;
     apr_pool_t *pool;
+    apr_allocator_t *allocator;
+    serf_bucket_alloc_t *serf_allocator;
+    serf_context_t *context;
     serf_connection_t *connection;
-    serf_request_t *request;
+    serf_bucket_t *request;
     serf_response_t *response;
     serf_filter_t *filter;
     apr_uri_t *url;
     const char *raw_url;
     int using_ssl = 0;
-   
+
     if (argc != 2) {
         puts("Gimme a URL, stupid!");
         exit(-1);
@@ -330,6 +357,40 @@
         using_ssl = 1;
     }
 #endif
+
+    context = serf_context_create(pool);
+    status = apr_allocator_create(&allocator);
+    if (status) {
+        printf("Error: %d\n", status);
+        exit(status);
+    }
+
+    serf_allocator = serf_bucket_allocator_create(allocator, pool);
+
+    connection = serf_connection_create(context, address, accept_response,
+                                        NULL, closed_connection, NULL, pool);
+
+    request = serf_bucket_request_create("GET", url->path, NULL,
+                                         serf_allocator);
+
+    serf_bucket_set_metadata(request, SERF_REQUEST_HEADERS, "User-Agent",
+                             "Serf" SERF_VERSION_STRING);
+
+    status = serf_connection_request_create(connection, request,
+                                            handle_response, NULL,
+                                            serf_allocator, pool);
+
+    if (status) {
+        printf("Error: %d\n", status);
+        exit(status);
+    }
+
+    status = serf_context_run(context, SERF_DURATION_FOREVER, pool);
+
+    if (status) {
+        printf("Error: %d\n", status);
+        exit(status);
+    }
 
     status = serf_open_uri(url, &connection, &request, pool);