summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralex <alex>2000-12-06 22:28:48 +0000
committeralex <alex>2000-12-06 22:28:48 +0000
commitee40cef78df148f9f96978e0be9e591edfa5853d (patch)
tree0ca7a10fffde54a3756c220a1707f84c1f4d7116
downloadlibsoup-ee40cef78df148f9f96978e0be9e591edfa5853d.tar.gz
Initial version
-rw-r--r--AUTHORS5
-rw-r--r--ChangeLog0
-rw-r--r--Makefile.am28
-rw-r--r--NEWS0
-rw-r--r--README0
-rwxr-xr-xautogen.sh148
-rw-r--r--configure.in179
-rw-r--r--libsoup/Makefile.am29
-rw-r--r--libsoup/soup-context.c182
-rw-r--r--libsoup/soup-context.h52
-rw-r--r--libsoup/soup-private.h65
-rw-r--r--libsoup/soup-queue.c236
-rw-r--r--libsoup/soup-queue.h53
-rw-r--r--libsoup/soup-uri.c189
-rw-r--r--libsoup/soup-uri.h63
-rw-r--r--libsoup/soup.h20
16 files changed, 1249 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..1139aa67
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+SOUP Authors
+============
+
+Alex Graveley <alex@helixcode.com>
+Miguel De Icaza <miguel@helixcode.com>
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ChangeLog
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 00000000..45d5428d
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,28 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = src
+
+EXTRA_DIST = \
+ autogen.sh
+
+install-data-local:
+ @$(NORMAL_INSTALL)
+ if test -d $(srcdir)/pixmaps; then \
+ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/pixmaps; \
+ for pixmap in $(srcdir)/pixmaps/*; do \
+ if test -f $$pixmap; then \
+ $(INSTALL_DATA) $$pixmap $(DESTDIR)$(pkgdatadir)/pixmaps; \
+ fi \
+ done \
+ fi
+
+dist-hook:
+ if test -d pixmaps; then \
+ mkdir $(distdir)/pixmaps; \
+ for pixmap in pixmaps/*; do \
+ if test -f $$pixmap; then \
+ cp -p $$pixmap $(distdir)/pixmaps; \
+ fi \
+ done \
+ fi
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/README
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 00000000..293b7972
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,148 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+PKG_NAME="the package."
+
+DIE=0
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`autoconf' installed to."
+ echo "Download the appropriate package for your distribution,"
+ echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+}
+
+(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && {
+ (libtool --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`libtool' installed."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+ }
+}
+
+grep "^AM_GNU_GETTEXT" $srcdir/configure.in >/dev/null && {
+ grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \
+ (gettext --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`gettext' installed."
+ echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+ }
+}
+
+grep "^AM_GNOME_GETTEXT" $srcdir/configure.in >/dev/null && {
+ grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \
+ (gettext --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`gettext' installed."
+ echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+ }
+}
+
+(automake --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`automake' installed."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+ NO_AUTOMAKE=yes
+}
+
+
+# if no automake, don't bother testing for aclocal
+test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: Missing \`aclocal'. The version of \`automake'"
+ echo "installed doesn't appear recent enough."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+}
+
+if test "$DIE" -eq 1; then
+ exit 1
+fi
+
+if test -z "$*"; then
+ echo "**Warning**: I am going to run \`configure' with no arguments."
+ echo "If you wish to pass any to it, please specify them on the"
+ echo \`$0\'" command line."
+ echo
+fi
+
+case $CC in
+xlc )
+ am_opt=--include-deps;;
+esac
+
+for coin in `find $srcdir -name configure.in -print`
+do
+ dr=`dirname $coin`
+ if test -f $dr/NO-AUTO-GEN; then
+ echo skipping $dr -- flagged as no auto-gen
+ else
+ echo processing $dr
+ macrodirs=`sed -n -e 's,AM_ACLOCAL_INCLUDE(\(.*\)),\1,gp' < $coin`
+ ( cd $dr
+ aclocalinclude="$ACLOCAL_FLAGS"
+ for k in $macrodirs; do
+ if test -d $k; then
+ aclocalinclude="$aclocalinclude -I $k"
+ ##else
+ ## echo "**Warning**: No such directory \`$k'. Ignored."
+ fi
+ done
+ if grep "^AM_GNU_GETTEXT" configure.in >/dev/null; then
+ if grep "sed.*POTFILES" configure.in >/dev/null; then
+ : do nothing -- we still have an old unmodified configure.in
+ else
+ echo "Creating $dr/aclocal.m4 ..."
+ test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
+ echo "Running gettextize... Ignore non-fatal messages."
+ echo "no" | gettextize --force --copy
+ echo "Making $dr/aclocal.m4 writable ..."
+ test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+ fi
+ fi
+ if grep "^AM_GNOME_GETTEXT" configure.in >/dev/null; then
+ echo "Creating $dr/aclocal.m4 ..."
+ test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
+ echo "Running gettextize... Ignore non-fatal messages."
+ echo "no" | gettextize --force --copy
+ echo "Making $dr/aclocal.m4 writable ..."
+ test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+ fi
+ if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then
+ echo "Running libtoolize..."
+ libtoolize --force --copy
+ fi
+ echo "Running aclocal $aclocalinclude ..."
+ aclocal $aclocalinclude
+ if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then
+ echo "Running autoheader..."
+ autoheader
+ fi
+ echo "Running automake --gnu $am_opt ..."
+ automake --add-missing --gnu $am_opt
+ echo "Running autoconf ..."
+ autoconf
+ )
+ fi
+done
+
+#conf_flags="--enable-maintainer-mode --enable-compile-warnings" #--enable-iso-c
+
+if test x$NOCONFIGURE = x; then
+ echo Running $srcdir/configure $conf_flags "$@" ...
+ $srcdir/configure $conf_flags "$@" \
+ && echo Now type \`make\' to compile $PKG_NAME
+else
+ echo Skipping configure process.
+fi
diff --git a/configure.in b/configure.in
new file mode 100644
index 00000000..33cce22d
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,179 @@
+# Process this file with autoconf to produce a configure script.
+
+# This is almost a direct rip-off of Gnet's configure.in
+
+# Require autoconf 2.13
+AC_PREREQ(2.13)
+
+# Initialize autoconf
+AC_INIT(src/soup.h)
+
+
+# On making releases:
+# SOUP_MICRO_VERSION += 1;
+# SOUP_INTERFACE_AGE += 1;
+# SOUP_BINARY_AGE += 1;
+# if any functions have been added, set SOUP_INTERFACE_AGE to 0.
+# if backwards compatibility has been broken,
+# set SOUP_BINARY_AGE _and_ SOUP_INTERFACE_AGE to 0.
+
+AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)
+SOUP_MAJOR_VERSION=0
+SOUP_MINOR_VERSION=1
+SOUP_MICRO_VERSION=5
+SOUP_INTERFACE_AGE=0
+SOUP_BINARY_AGE=0
+SOUP_VERSION=$SOUP_MAJOR_VERSION.$SOUP_MINOR_VERSION.$SOUP_MICRO_VERSION
+AC_DIVERT_POP()
+
+AC_SUBST(SOUP_MAJOR_VERSION)
+AC_SUBST(SOUP_MINOR_VERSION)
+AC_SUBST(SOUP_MICRO_VERSION)
+AC_SUBST(SOUP_VERSION)
+AC_SUBST(SOUP_INTERFACE_AGE)
+AC_SUBST(SOUP_BINARY_AGE)
+
+# libtool versioning
+LT_RELEASE=$SOUP_MAJOR_VERSION.$SOUP_MINOR_VERSION
+LT_CURRENT=`expr $SOUP_MICRO_VERSION - $SOUP_INTERFACE_AGE`
+LT_REVISION=$SOUP_INTERFACE_AGE
+LT_AGE=`expr $SOUP_BINARY_AGE - $SOUP_INTERFACE_AGE`
+AC_SUBST(LT_RELEASE)
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+AC_SUBST(LT_AGE)
+
+VERSION=$SOUP_VERSION
+PACKAGE=soup
+
+# Specify a configuration file
+AM_CONFIG_HEADER(config.h)
+
+# Define version stuff
+AC_DEFINE_UNQUOTED(SOUP_MAJOR_VERSION, $SOUP_MAJOR_VERSION)
+AC_DEFINE_UNQUOTED(SOUP_MINOR_VERSION, $SOUP_MINOR_VERSION)
+AC_DEFINE_UNQUOTED(SOUP_MICRO_VERSION, $SOUP_MICRO_VERSION)
+AC_DEFINE_UNQUOTED(SOUP_INTERFACE_AGE, $SOUP_INTERFACE_AGE)
+AC_DEFINE_UNQUOTED(SOUP_BINARY_AGE, $SOUP_BINARY_AGE)
+
+# Initialize automake
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define)
+
+# Initialize maintainer mode
+AM_MAINTAINER_MODE
+
+
+# ****************************************
+# Set debugging flags
+
+# Figure out debugging default, prior to $ac_help setup
+AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl
+if test `expr $SOUP_MINOR_VERSION \% 2` = 1 ; then
+ debug_default=yes
+else
+ debug_default=minimum
+fi
+AC_DIVERT_POP()
+
+# Declare --enable-* args and collect ac_help strings
+AC_ARG_ENABLE(debug, [ --enable-debug=[no/minimum/yes] turn on debugging [default=$debug_default]],,enable_debug=$debug_default)
+
+# Set the debug flags
+AC_MSG_CHECKING(for --enable-debug)
+if test "x$enable_debug" = "xyes"; then
+ test "$cflags_set" = set || CFLAGS="$CFLAGS -g"
+ SOUP_DEBUG_FLAGS="-DG_ENABLE_DEBUG"
+ AC_MSG_RESULT(yes)
+else
+ if test "x$enable_debug" = "xno"; then
+ SOUP_DEBUG_FLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS"
+ AC_MSG_RESULT(no)
+ fi
+fi
+
+AC_SUBST(SOUP_DEBUG_FLAGS)
+
+
+# ****************************************
+# Check for programs
+
+AC_PROG_CC
+AM_PROG_CC_STDC
+AC_PROG_INSTALL
+
+# Use an many warnings as possible
+changequote(,)
+if test "x$GCC" = "xyes"; then
+ case " $CFLAGS " in
+ *[\ \ ]-Wall[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -Wall" ;;
+ esac
+
+ if test "x$enable_ansi" = "xyes"; then
+ case " $CFLAGS " in
+ *[\ \ ]-ansi[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -ansi" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[\ \ ]-pedantic[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS -pedantic" ;;
+ esac
+ fi
+fi
+changequote([,])
+
+# Use reentrant functions
+CFLAGS="$CFLAGS -D_REENTRANT"
+
+# Set STDC_HEADERS
+AC_HEADER_STDC
+
+# Initialize libtool
+AM_PROG_LIBTOOL
+
+
+# ****************************************
+# Check for libraries
+
+# Need GLIB
+AM_PATH_GLIB(1.2.0,
+ [LIBS="$LIBS $GLIB_LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS"],
+ AC_MSG_ERROR(Cannot find GLIB: Is glib-config in path?))
+
+GLIB_CFLAGS=`glib-config --cflags glib`
+GLIB_LIBS=`glib-config --libs glib`
+
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+
+# Need GNET
+AM_PATH_GNET(1.0.0,
+ [LIBS="$LIBS $GNET_LIBS" CFLAGS="$CFLAGS $GNET_CFLAGS"],
+ AC_MSG_ERROR(Cannot find GNET: Is gnet-config in path?))
+
+GNET_CFLAGS=`gnet-config --cflags gnet`
+GNET_LIBS=`gnet-config --libs gnet`
+
+AC_SUBST(GNET_CFLAGS)
+AC_SUBST(GNET_LIBS)
+
+
+# Set PACKAGE_SOURCE_DIR in config.h.
+packagesrcdir=`cd $srcdir && pwd`
+AC_DEFINE_UNQUOTED(PACKAGE_SOURCE_DIR, "${packagesrcdir}")
+
+# If gcc is the compiler, compile with lots of warnings
+if test "x$GCC" = "xyes"; then
+ CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations "
+fi
+
+# doc/Makefile
+# gnome-soup.spec
+
+AC_OUTPUT([
+ Makefile
+ src/Makefile
+])
+
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
new file mode 100644
index 00000000..052135c3
--- /dev/null
+++ b/libsoup/Makefile.am
@@ -0,0 +1,29 @@
+## Process this file with automake to produce Makefile.in
+
+@SET_MAKE@
+
+INCLUDES = -DG_LOG_DOMAIN=\"SOUP\" @SOUP_DEBUG_FLAGS@
+
+soupincludedir = $(includedir)/soup
+
+lib_LTLIBRARIES = libsoup.la
+
+libsoup_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -release $(LT_RELEASE)
+
+libsoup_la_SOURCES = \
+ soup-context.c \
+ soup-queue.c \
+ soup-request.c \
+ soup-uri.c
+
+soupinclude_HEADERS = \
+ soup.h \
+ soup-context.h \
+ soup-queue.h \
+ soup-request.h \
+ soup-uri.h
+
+EXTRA_DIST = soup-private.h
+
diff --git a/libsoup/soup-context.c b/libsoup/soup-context.c
new file mode 100644
index 00000000..6353f1bb
--- /dev/null
+++ b/libsoup/soup-context.c
@@ -0,0 +1,182 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-queue.c: Asyncronous Callback-based SOAP Request Queue.
+ *
+ * Authors:
+ * Alex Graveley (alex@helixcode.com)
+ *
+ * Copyright (C) 2000, Helix Code, Inc.
+ */
+
+#include <gnet/gnet.h>
+
+#include "soup-context.h"
+#include "soup-private.h"
+#include "soup-uri.h"
+
+GHashTable *servers;
+
+static SoupContext *
+soup_context_new (SoupServer *server, SoupUri *uri)
+{
+ SoupContext *ctx = g_new0 (SoupContext, 1);
+ ctx->priv = g_new0 (SoupContextPrivate, 1);
+ ctx->priv->server = server;
+ ctx->priv->keep_alive = TRUE;
+ ctx->priv->chunk_size = DEFAULT_CHUNK_SIZE;
+ ctx->uri = uri;
+ ctx->custom_headers = NULL;
+ return ctx;
+}
+
+SoupContext *
+soup_context_get (gchar *uri)
+{
+ SoupServer *serv;
+ SoupContext *ret = NULL;
+ SoupUri *suri = soup_uri_new (uri);
+
+ if (!servers)
+ servers = g_hash_table_new (g_str_hash, g_str_equal);
+ else
+ serv = g_hash_table_lookup (servers, suri->host);
+
+ if (serv) {
+ if (serv->contexts)
+ ret = g_hash_table_lookup (serv->contexts, suri->path);
+ else
+ serv->contexts = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ } else {
+ serv = g_new0 (SoupServer, 1);
+ serv->host = g_strdup (suri->host);
+ g_hash_table_insert (servers, suri->host, serv);
+ }
+
+ if (ret) return ret;
+
+ ret = soup_context_new (serv, suri);
+
+ g_hash_table_insert (serv->contexts, suri->path, ret);
+
+ return ret;
+}
+
+void
+soup_context_free (SoupContext *ctx)
+{
+}
+
+struct SoupContextConnectFunctor {
+ SoupContext *ctx;
+ SoupConnectCallbackFn cb;
+ gpointer user_data;
+};
+
+static void
+soup_context_connect_cb (GTcpSocket *socket,
+ GInetAddr* addr,
+ GTcpSocketConnectAsyncStatus status,
+ gpointer user_data)
+{
+ struct SoupContextConnectFunctor *data = user_data;
+ SoupContext *ctx = data->ctx;
+ SoupConnectCallbackFn cb = data->cb;
+ gpointer cb_data = data->user_data;
+ SoupConnection *new_conn;
+
+ g_free (data);
+
+ gnet_inetaddr_unref(addr);
+
+ switch (status) {
+ case GTCP_SOCKET_CONNECT_ASYNC_STATUS_OK:
+ new_conn = g_new0 (SoupConnection, 1);
+ new_conn->port = ctx->uri->port;
+ new_conn->in_use = TRUE;
+ new_conn->socket = socket;
+
+ ctx->priv->server->connections =
+ g_slist_prepend (ctx->priv->server->connections,
+ new_conn);
+
+ (*cb) (ctx, SOUP_CONNECT_ERROR_NONE, socket, cb_data);
+ break;
+ case GTCP_SOCKET_CONNECT_ASYNC_STATUS_INETADDR_ERROR:
+ (*cb) (ctx, SOUP_CONNECT_ERROR_ADDR_RESOLVE, NULL, cb_data);
+ break;
+ case GTCP_SOCKET_CONNECT_ASYNC_STATUS_TCP_ERROR:
+ (*cb) (ctx, SOUP_CONNECT_ERROR_NETWORK, NULL, cb_data);
+ break;
+ }
+}
+
+void
+soup_context_get_connection (SoupContext *ctx,
+ SoupConnectCallbackFn cb,
+ gpointer user_data)
+{
+ GSList *conns;
+
+ if (!ctx->priv->keep_alive)
+ goto FORCE_NEW_CONNECTION;
+
+ conns = ctx->priv->server->connections;
+
+ while (conns) {
+ SoupConnection *conn = conns->data;
+
+ if (!conn->in_use && conn->port == ctx->uri->port) {
+ conn->in_use = TRUE;
+ (*cb) (ctx,
+ SOUP_CONNECT_ERROR_NONE,
+ conn->socket,
+ user_data);
+ return;
+ }
+
+ conns = conns->next;
+ }
+
+ FORCE_NEW_CONNECTION:
+ {
+ struct SoupContextConnectFunctor *data;
+ data = g_new0 (struct SoupContextConnectFunctor, 1);
+ data->ctx = ctx;
+ data->cb = cb;
+ data->user_data = user_data;
+ gnet_tcp_socket_connect_async (ctx->uri->host,
+ ctx->uri->port,
+ soup_context_connect_cb,
+ user_data);
+ return;
+ }
+}
+
+void
+soup_context_return_connection (SoupContext *ctx,
+ GTcpSocket *socket)
+{
+ SoupServer *server = ctx->priv->server;
+ GSList *conns = server->connections;
+
+ while (conns) {
+ SoupConnection *conn = conns->data;
+
+ if (conn->socket == socket) {
+ if (ctx->priv->keep_alive) {
+ conn->in_use = FALSE;
+ } else {
+ server->connections =
+ g_slist_remove (server->connections,
+ socket);
+ gnet_tcp_socket_unref (socket);
+ connection_count--;
+ }
+
+ return;
+ }
+
+ conns = conns->next;
+ }
+}
diff --git a/libsoup/soup-context.h b/libsoup/soup-context.h
new file mode 100644
index 00000000..c1f95e6a
--- /dev/null
+++ b/libsoup/soup-context.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ *
+ * Authors:
+ * Alex Graveley (alex@helixcode.com)
+ *
+ * Copyright (C) 2000, Helix Code, Inc.
+ */
+
+#ifndef SOUP_CONTEXT_H
+#define SOUP_CONTEXT_H 1
+
+#include <glib.h>
+
+#include "soup-uri.h"
+
+typedef struct _SoupContextPrivate SoupContextPrivate;
+
+typedef struct {
+ SoupContextPrivate *priv;
+ SoupUri *uri;
+ GList *custom_headers;
+} SoupContext;
+
+typedef enum {
+ SOUP_CONNECT_ERROR_NONE,
+ SOUP_CONNECT_ERROR_ADDR_RESOLVE,
+ SOUP_CONNECT_ERROR_NETWORK
+} SoupConnectErrorCode;
+
+typedef void (*SoupConnectCallbackFn) (SoupContext *ctx,
+ SoupConnectErrorCode err,
+ GTcpSocket *socket,
+ gpointer user_data);
+
+SoupContext *soup_context_get (gchar *uri);
+
+void soup_context_free (SoupContext *ctx);
+
+void soup_context_add_header (SoupContext *ctx,
+ gchar *name,
+ gchar *value);
+
+void soup_context_get_connection (SoupContext *ctx,
+ SoupConnectCallbackFn cb,
+ gpointer user_data);
+
+void soup_context_return_connection (SoupContext *ctx,
+ GTcpSocket *socket);
+
+#endif /*SOUP_CONTEXT_H*/
diff --git a/libsoup/soup-private.h b/libsoup/soup-private.h
new file mode 100644
index 00000000..be3b7f4e
--- /dev/null
+++ b/libsoup/soup-private.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ *
+ * Authors:
+ * Alex Graveley (alex@helixcode.com)
+ *
+ * Copyright (C) 2000, Helix Code, Inc.
+ */
+
+/*
+ * All the things SOUP users shouldn't need to know about except under
+ * extraneous circumstances.
+ */
+
+#ifndef SOAP_PRIVATE_H
+#define SOAP_PRIVATE_H 1
+
+#include "soup-queue.h"
+
+#define DEFAULT_CHUNK_SIZE 1024
+#define RESPONSE_BLOCK_SIZE 1024
+
+typedef struct {
+ guint port;
+ gboolean in_use;
+ GTcpSocket *socket;
+} SoupConnection;
+
+typedef struct {
+ gchar *host;
+ GSList *connections; /* CONTAINS: SoupConnection */
+ GHashTable *contexts; /* KEY: uri->path, VALUE: SoupContext */
+} SoupServer;
+
+extern GHashTable *servers;
+extern guint connection_count;
+extern GList *active_requests;
+
+struct _SoupContextPrivate {
+ SoupServer *server;
+
+ gboolean keep_alive;
+ gint chunk_size;
+};
+
+struct _SoupRequestPrivate {
+ GTcpSocket *socket;
+
+ gulong write_len;
+ gulong read_len;
+
+ guint connect_tag;
+ guint read_tag;
+ guint write_tag;
+ guint timeout_tag;
+
+ SoupCallbackFn callback;
+ gpointer user_data;
+};
+
+SoupCallbackResult soup_request_issue_callback (SoupRequest *req,
+ SoupErrorCode error);
+
+#endif /*SOUP_PRIVATE_H*/
diff --git a/libsoup/soup-queue.c b/libsoup/soup-queue.c
new file mode 100644
index 00000000..7319a389
--- /dev/null
+++ b/libsoup/soup-queue.c
@@ -0,0 +1,236 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-queue.c: Asyncronous Callback-based SOAP Request Queue.
+ *
+ * Authors:
+ * Alex Graveley (alex@helixcode.com)
+ *
+ * Copyright (C) 2000, Helix Code, Inc.
+ */
+
+#include <glib.h>
+#include <gnet/gnet.h>
+
+#include "soup-queue.h"
+#include "soup-context.h"
+#include "soup-private.h"
+
+guint connection_count = 0;
+
+GList *active_requests = NULL;
+
+static guint max_connections = 4;
+
+static guint soup_queue_idle_tag = 0;
+
+static SoupContext *proxy_context;
+
+static gboolean
+soup_queue_read_async (GIOChannel* iochannel,
+ GIOCondition condition,
+ SoupRequest *req)
+{
+ guint bytes_read;
+ GIOError error;
+
+ if (!req->response.body) {
+ req->response.body = g_malloc (RESPONSE_BLOCK_SIZE);
+ req->response.length = RESPONSE_BLOCK_SIZE;
+ } else if (req->priv->read_len == req->response.length) {
+ req->response.length += RESPONSE_BLOCK_SIZE;
+ req->response.body = g_realloc (req->response.body,
+ req->response.length);
+ }
+
+ error = g_io_channel_read (iochannel,
+ &req->response.body[req->priv->read_len],
+ req->response.length - req->priv->read_len,
+ &bytes_read);
+
+ if (error == G_IO_ERROR_AGAIN)
+ return TRUE;
+
+ if (error != G_IO_ERROR_NONE) {
+ soup_request_issue_callback (req, SOUP_ERROR_IO);
+ return FALSE;
+ }
+
+ if (bytes_read == 0) {
+ req->status = SOUP_STATUS_FINISHED;
+ soup_request_issue_callback (req, SOUP_ERROR_NONE);
+ return FALSE;
+ }
+
+ req->priv->read_len += bytes_read;
+
+ return TRUE;
+}
+
+static gboolean
+soup_queue_write_async (GIOChannel* iochannel,
+ GIOCondition condition,
+ SoupRequest *req)
+{
+ guint bytes_written;
+ GIOError error;
+
+ error = g_io_channel_write (iochannel,
+ &req->request.body[req->priv->write_len],
+ req->request.length - req->priv->write_len,
+ &bytes_written);
+
+ if (error == G_IO_ERROR_AGAIN)
+ return TRUE;
+
+ if (error != G_IO_ERROR_NONE) {
+ soup_request_issue_callback (req, SOUP_ERROR_IO);
+ return FALSE;
+ }
+
+ req->priv->write_len += bytes_written;
+
+ if (req->priv->write_len == req->request.length) {
+ req->status = SOUP_STATUS_READING_RESPONSE;
+ req->priv->read_tag =
+ g_io_add_watch (iochannel,
+ G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+ (GIOFunc) soup_queue_read_async,
+ req);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+soup_queue_connect (SoupContext *ctx,
+ SoupConnectErrorCode err,
+ GTcpSocket *socket,
+ gpointer user_data)
+{
+ SoupRequest *req = user_data;
+ GIOChannel *channel;
+
+ switch (err) {
+ case SOUP_CONNECT_ERROR_NONE:
+ channel = gnet_tcp_socket_get_iochannel (socket);
+
+ gnet_tcp_socket_set_tos (socket, GNET_TOS_LOWDELAY);
+
+ req->status = SOUP_STATUS_SENDING_REQUEST;
+ req->priv->socket = socket;
+ req->priv->write_tag =
+ g_io_add_watch (channel,
+ G_IO_OUT|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+ (GIOFunc) soup_queue_write_async,
+ req);
+ break;
+ case SOUP_CONNECT_ERROR_ADDR_RESOLVE:
+ case SOUP_CONNECT_ERROR_NETWORK:
+ soup_request_issue_callback (req, SOUP_ERROR_CANT_CONNECT);
+ connection_count--;
+ break;
+ }
+}
+
+static gboolean
+soup_idle_handle_new_requests (gpointer unused)
+{
+ GList *iter;
+ gboolean work_to_do = FALSE;
+
+ if (connection_count >= max_connections)
+ return TRUE;
+
+ for (iter = active_requests; iter; iter = iter->next) {
+ SoupRequest *req = iter->data;
+
+ if (connection_count >= max_connections)
+ return TRUE;
+
+ if (req->status != SOUP_STATUS_QUEUED)
+ continue;
+
+ if (req->priv->socket) {
+ GTcpSocket *sock = req->priv->socket;
+ GIOChannel *channel;
+ channel = gnet_tcp_socket_get_iochannel (sock);
+
+ req->status = SOUP_STATUS_SENDING_REQUEST;
+ req->priv->write_tag = g_io_add_watch (
+ channel,
+ G_IO_OUT|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+ (GIOFunc) soup_queue_write_async,
+ req);
+ } else {
+ SoupContext *ctx;
+ ctx = proxy_context ? proxy_context : req->context;
+ connection_count++;
+
+ req->status = SOUP_STATUS_CONNECTING;
+ soup_context_get_connection (ctx,
+ soup_queue_connect,
+ req);
+ }
+
+ work_to_do = TRUE;
+ }
+
+ if (!work_to_do) {
+ soup_queue_idle_tag = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+soup_queue_request (SoupRequest *req,
+ SoupCallbackFn callback,
+ gpointer user_data)
+{
+ if (!soup_queue_idle_tag)
+ soup_queue_idle_tag =
+ g_idle_add (soup_idle_handle_new_requests, NULL);
+
+ if (req->response.body &&
+ req->response.owner == SOUP_BUFFER_SYSTEM_OWNED) {
+ g_free (req->response.body);
+ req->response.body = NULL;
+ req->response.length = 0;
+ }
+
+ req->priv->callback = callback;
+ req->priv->user_data = user_data;
+ req->status = SOUP_STATUS_QUEUED;
+
+ active_requests = g_list_append (active_requests, req);
+}
+
+void
+soup_queue_shutdown ()
+{
+ GList *iter;
+
+ g_source_remove (soup_queue_idle_tag);
+ soup_queue_idle_tag = 0;
+
+ for (iter = active_requests; iter; iter = iter->next)
+ soup_request_cancel (iter->data);
+}
+
+void
+soup_queue_set_proxy (SoupContext *context)
+{
+ if (proxy_context)
+ soup_context_free (proxy_context);
+
+ proxy_context = context;
+}
+
+SoupContext *
+soup_queue_get_proxy ()
+{
+ return proxy_context;
+}
+
diff --git a/libsoup/soup-queue.h b/libsoup/soup-queue.h
new file mode 100644
index 00000000..1b6664a9
--- /dev/null
+++ b/libsoup/soup-queue.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ *
+ * Authors:
+ * Alex Graveley (alex@helixcode.com)
+ *
+ * Copyright (C) 2000, Helix Code, Inc.
+ */
+
+#ifndef SOUP_QUEUE_H
+#define SOUP_QUEUE_H 1
+
+#include <glib.h>
+
+#include "soup-request.h"
+#include "soup-context.h"
+
+typedef enum {
+ SOUP_RESULT_FREE_REQUEST = 0,
+ SOUP_RESULT_RESEND_REQUEST,
+ SOUP_RESULT_DO_NOTHING
+} SoupCallbackResult;
+
+typedef enum {
+ SOUP_ERROR_NONE = 0,
+ SOUP_ERROR_CANCELLED,
+ SOUP_ERROR_CANT_CONNECT,
+ SOUP_ERROR_URI_NOT_FOUND,
+ SOUP_ERROR_URI_NOT_PERMITTED,
+ SOUP_ERROR_URI_OBJECT_MOVED,
+ SOUP_ERROR_IO,
+ SOUP_ERROR_MALFORMED_HEADER,
+ SOUP_ERROR_UNKNOWN
+} SoupErrorCode;
+
+typedef SoupCallbackResult (*SoupCallbackFn) (SoupRequest *req,
+ SoupErrorCode err,
+ gpointer user_data);
+
+void soup_queue_request (SoupRequest *req,
+ SoupCallbackFn callback,
+ gpointer user_data);
+
+void soup_queue_cancel_request (SoupRequest *req);
+
+void soup_queue_set_proxy (SoupContext *ctx);
+
+SoupContext *soup_queue_get_proxy (void);
+
+void soup_queue_shutdown (void);
+
+#endif /* SOUP_QUEUE_H */
diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c
new file mode 100644
index 00000000..31a2aca0
--- /dev/null
+++ b/libsoup/soup-uri.c
@@ -0,0 +1,189 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* soup-uri.c : utility functions to parse URLs */
+
+/*
+ * Authors :
+ * Bertrand Guiheneuf <bertrand@helixcode.com>
+ * Dan Winship <danw@helixcode.com>
+ *
+ * Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+
+/*
+ * Here we deal with URLs following the general scheme:
+ * protocol://user;AUTH=mech:password@host:port/name
+ * where name is a path-like string (ie dir1/dir2/....) See RFC 1738
+ * for the complete description of Uniform Resource Locators. The
+ * ";AUTH=mech" addition comes from RFC 2384, "POP URL Scheme".
+ */
+
+/* XXX TODO:
+ * recover the words between #'s or ?'s after the path
+ * % escapes
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "soup-uri.h"
+
+/**
+ * soup_uri_new: create a Gurl object from a string
+ *
+ * @uri_string: The string containing the URL to scan
+ *
+ * This routine takes a gchar and parses it as a
+ * URL of the form:
+ * protocol://user;AUTH=mech:password@host:port/path
+ * There is no test on the values. For example,
+ * "port" can be a string, not only a number!
+ * The Gurl structure fields are filled with
+ * the scan results. When a member of the
+ * general URL can not be found, the corresponding
+ * Gurl member is NULL.
+ * Fields filled in the Gurl structure are allocated
+ * and url_string is not modified.
+ *
+ * Return value: a Gurl structure containing the URL items.
+ **/
+SoupUri *soup_uri_new (const gchar* uri_string)
+{
+ SoupUri *g_uri;
+ char *semi, *colon, *at, *slash, *path;
+ char **split;
+
+ g_uri = g_new (SoupUri,1);
+
+ /* Find protocol: initial substring until "://" */
+ colon = strchr (uri_string, ':');
+ if (colon && !strncmp (colon, "://", 3)) {
+ g_uri->protocol = g_strndup (uri_string, colon - uri_string);
+ uri_string = colon + 3;
+ } else
+ g_uri->protocol = NULL;
+
+ /* If there is an @ sign, look for user, authmech, and
+ * password before it.
+ */
+ at = strchr (uri_string, '@');
+ if (at) {
+ colon = strchr (uri_string, ':');
+ if (colon && colon < at)
+ g_uri->passwd = g_strndup (colon + 1, at - colon - 1);
+ else {
+ g_uri->passwd = NULL;
+ colon = at;
+ }
+
+ semi = strchr(uri_string, ';');
+ if (semi && semi < colon && !strncasecmp (semi, ";auth=", 6))
+ g_uri->authmech = g_strndup (semi + 6, colon - semi - 6);
+ else {
+ g_uri->authmech = NULL;
+ semi = colon;
+ }
+
+ g_uri->user = g_strndup (uri_string, semi - uri_string);
+ uri_string = at + 1;
+ } else
+ g_uri->user = g_uri->passwd = g_uri->authmech = NULL;
+
+ /* Find host (required) and port. */
+ slash = strchr (uri_string, '/');
+ colon = strchr (uri_string, ':');
+ if (slash && colon > slash)
+ colon = 0;
+
+ if (colon) {
+ g_uri->host = g_strndup (uri_string, colon - uri_string);
+ if (slash)
+ g_uri->port = atoi(colon + 1);
+ else
+ g_uri->port = atoi(colon + 1);
+ } else if (slash) {
+ g_uri->host = g_strndup (uri_string, slash - uri_string);
+ g_uri->port = -1;
+ } else {
+ g_uri->host = g_strdup (uri_string);
+ g_uri->port = -1;
+ }
+
+ /* setup a fallback, if relative, then empty string, else
+ it will be from root */
+ if (slash == NULL) {
+ slash = "/";
+ }
+ if (slash && *slash && g_uri->protocol == NULL)
+ slash++;
+
+ split = g_strsplit(slash, " ", 0);
+ path = g_strjoinv("%20", split);
+ g_strfreev(split);
+
+ g_uri->path = path;
+
+ return g_uri;
+}
+
+gchar *
+soup_uri_to_string (const SoupUri *uri, gboolean show_passwd)
+{
+ if (uri->port != -1)
+ return g_strdup_printf(
+ "%s%s%s%s%s%s%s%s%s:%d%s",
+ uri->protocol ? uri->protocol : "",
+ uri->protocol ? "://" : "",
+ uri->user ? uri->user : "",
+ uri->authmech ? ";auth=" : "",
+ uri->authmech ? uri->authmech : "",
+ uri->passwd && show_passwd ? ":" : "",
+ uri->passwd && show_passwd ? uri->passwd : "",
+ uri->user ? "@" : "",
+ uri->host,
+ uri->port,
+ uri->path ? uri->path : "");
+ else
+ return g_strdup_printf(
+ "%s%s%s%s%s%s%s%s%s%s",
+ uri->protocol ? uri->protocol : "",
+ uri->protocol ? "://" : "",
+ uri->user ? uri->user : "",
+ uri->authmech ? ";auth=" : "",
+ uri->authmech ? uri->authmech : "",
+ uri->passwd && show_passwd ? ":" : "",
+ uri->passwd && show_passwd ? uri->passwd : "",
+ uri->user ? "@" : "",
+ uri->host,
+ uri->path ? uri->path : "");
+}
+
+void
+soup_uri_free (SoupUri *uri)
+{
+ g_assert (uri);
+
+ g_free (uri->protocol);
+ g_free (uri->user);
+ g_free (uri->authmech);
+ g_free (uri->passwd);
+ g_free (uri->host);
+ g_free (uri->path);
+
+ g_free (uri);
+}
diff --git a/libsoup/soup-uri.h b/libsoup/soup-uri.h
new file mode 100644
index 00000000..a37b684c
--- /dev/null
+++ b/libsoup/soup-uri.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* url-util.h : utility functions to parse URLs */
+
+/*
+ * Author :
+ * Bertrand Guiheneuf <bertrand@helixcode.com>
+ *
+ * Copyright 1999, 2000 HelixCode (http://www.helixcode.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifndef SOUP_URI_H
+#define SOUP_URI_H 1
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+typedef struct {
+ gchar *protocol;
+ gchar *user;
+ gchar *authmech;
+ gchar *passwd;
+ gchar *host;
+ int port;
+ gchar *path;
+} SoupUri;
+
+/* the cache system has been disabled because it would
+ need the user to use accessors instead of modifying the
+ structure field. As the speed is not so important here,
+ I chose not to use it */
+
+SoupUri *soup_uri_new (const gchar *uri_string);
+
+gchar *soup_uri_to_string (const SoupUri *uri, gboolean show_password);
+
+void soup_uri_free (SoupUri *uri);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /*SOUP_URI_H*/
diff --git a/libsoup/soup.h b/libsoup/soup.h
new file mode 100644
index 00000000..d451e191
--- /dev/null
+++ b/libsoup/soup.h
@@ -0,0 +1,20 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ *
+ * Authors:
+ * Alex Graveley (alex@helixcode.com)
+ *
+ * Copyright (C) 2000, Helix Code, Inc.
+ */
+
+#ifndef SOUP_H
+#define SOUP_H 1
+
+#include "soup-queue.h"
+#include "soup-context.h"
+#include "soup-request.h"
+#include "soup-header.h"
+#include "soup-uri.h"
+
+#endif /*SOUP_H*/