[phodav] Handle PUT by incoming chunks
- From: Marc-Andre Lureau <malureau src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [phodav] Handle PUT by incoming chunks
- Date: Tue, 4 Mar 2014 13:12:45 +0000 (UTC)
commit 4dba2107ebacd835fee76aee797442532b8af84a
Author: Marc-André Lureau <marcandre lureau gmail com>
Date: Tue Mar 4 14:12:27 2014 +0100
Handle PUT by incoming chunks
Avoid growing a body buffer that could be very large
TODO | 1 -
libphodav/phodav-server.c | 145 ++++++++++++++++++++++++++++++++++-----------
2 files changed, 111 insertions(+), 35 deletions(-)
---
diff --git a/TODO b/TODO
index 73916be..3d3c322 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,3 @@
-- very large incoming data/copy (not buffer all in RAM)
- read/write offsets
- search
- subscribe/notify (perhaps not good enough imho) or equivalent
diff --git a/libphodav/phodav-server.c b/libphodav/phodav-server.c
index 577b026..eed8517 100644
--- a/libphodav/phodav-server.c
+++ b/libphodav/phodav-server.c
@@ -71,6 +71,11 @@ static void server_callback (SoupServer *server,
SoupClientContext *context,
gpointer user_data);
+static void request_started (SoupServer *server,
+ SoupMessage *message,
+ SoupClientContext *client,
+ gpointer user_data);
+
static void dav_lock_free (DAVLock *lock);
struct _Path
@@ -289,6 +294,7 @@ static void
phodav_server_constructed (GObject *gobject)
{
PhodavServer *self = PHODAV_SERVER (gobject);
+ PathHandler *handler = path_handler_new (self, g_file_new_for_path (self->path));
self->server = soup_server_new (SOUP_SERVER_PORT, self->port,
SOUP_SERVER_SERVER_HEADER, "PhodavServer ",
@@ -297,9 +303,11 @@ phodav_server_constructed (GObject *gobject)
soup_server_add_handler (self->server, NULL,
server_callback,
- path_handler_new (self, g_file_new_for_path (self->path)),
+ handler,
(GDestroyNotify) path_handler_free);
+ g_signal_connect (self->server, "request-started", G_CALLBACK (request_started), handler);
+
/* Chain up to the parent class */
if (G_OBJECT_CLASS (phodav_server_parent_class)->constructed)
G_OBJECT_CLASS (phodav_server_parent_class)->constructed (gobject);
@@ -1897,12 +1905,12 @@ method_get (PathHandler *handler, SoupMessage *msg, const char *path, GError **e
}
static gint
-do_put_file (SoupMessage *msg, GFile *file,
- GCancellable *cancellable, GError **err)
+put_start (SoupMessage *msg, GFile *file,
+ GFileOutputStream **output, GCancellable *cancellable,
+ GError **err)
{
- GFileOutputStream *s;
+ GFileOutputStream *s = NULL;
gchar *etag = NULL;
- gsize bytes_written;
gboolean created = TRUE;
SoupMessageHeaders *headers = msg->request_headers;
gint status = SOUP_STATUS_INTERNAL_SERVER_ERROR;
@@ -1921,15 +1929,10 @@ do_put_file (SoupMessage *msg, GFile *file,
if (!s)
goto end;
- if (!g_output_stream_write_all (G_OUTPUT_STREAM (s),
- msg->request_body->data, msg->request_body->length,
- &bytes_written, cancellable, err))
- goto end;
-
status = created ? SOUP_STATUS_CREATED : SOUP_STATUS_OK;
end:
- g_object_unref (s);
+ *output = s;
return status;
}
@@ -2348,27 +2351,6 @@ end:
}
static gint
-method_put (PathHandler *handler, SoupMessage *msg,
- const char *path, GError **err)
-{
- GFile *file;
- PhodavServer *self = handler->self;
- gint status;
- GList *submitted = NULL;
-
- status = check_if (handler, msg, path, &submitted);
- if (status != SOUP_STATUS_OK)
- goto end;
-
- file = g_file_get_child (handler->file, path + 1);
- status = do_put_file (msg, file, self->cancellable, err);
-
-end:
- g_clear_object (&file);
- return status;
-}
-
-static gint
do_mkcol_file (SoupMessage *msg, GFile *file,
GCancellable *cancellable, GError **err)
{
@@ -2913,6 +2895,103 @@ method_unlock (PathHandler *handler, SoupMessage *msg,
}
static void
+method_put_finished (SoupMessage *msg,
+ SoupBuffer *chunk,
+ gpointer user_data)
+{
+ GFileOutputStream *output = user_data;
+
+ g_debug ("PUT finished");
+
+ g_object_unref (output);
+}
+
+static void
+method_put_got_chunk (SoupMessage *msg,
+ SoupBuffer *chunk,
+ gpointer user_data)
+{
+ GFileOutputStream *output = user_data;
+ PathHandler *handler = g_object_get_data (user_data, "handler");
+ PhodavServer *self = handler->self;
+ GError *err = NULL;
+ gsize bytes_written;
+
+ g_debug ("PUT got chunk");
+
+ if (!g_output_stream_write_all (G_OUTPUT_STREAM (output),
+ chunk->data, chunk->length,
+ &bytes_written, self->cancellable, &err))
+ goto end;
+
+end:
+ if (err)
+ {
+ g_warning ("error: %s", err->message);
+ g_clear_error (&err);
+ soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ }
+}
+
+static void
+method_put (PathHandler *handler, const gchar *path, SoupMessage *msg, GError **err)
+{
+ PhodavServer *self = handler->self;
+ GFile *file = NULL;
+ GList *submitted = NULL;
+ GFileOutputStream *output = NULL;
+ gint status;
+
+ status = check_if (handler, msg, path, &submitted);
+ if (status != SOUP_STATUS_OK)
+ goto end;
+
+ file = g_file_get_child (handler->file, path + 1);
+ status = put_start (msg, file, &output, self->cancellable, err);
+ if (*err)
+ goto end;
+
+ soup_message_body_set_accumulate (msg->request_body, FALSE);
+ g_object_set_data (G_OBJECT (output), "handler", handler);
+ g_signal_connect (msg, "got-chunk", G_CALLBACK (method_put_got_chunk), output);
+ g_signal_connect (msg, "finished", G_CALLBACK (method_put_finished), output);
+
+end:
+ soup_message_set_status (msg, status);
+ g_clear_object (&file);
+}
+
+static void
+got_headers (SoupMessage *msg,
+ gpointer user_data)
+{
+ PathHandler *handler = user_data;
+ SoupURI *uri = soup_message_get_uri (msg);
+ const gchar *path = uri->path;
+ GError *err = NULL;
+
+ if (msg->method == SOUP_METHOD_PUT)
+ method_put (handler, path, msg, &err);
+
+ if (err)
+ {
+ g_warning ("error: %s", err->message);
+ g_clear_error (&err);
+ }
+}
+
+static void
+request_started (SoupServer *server,
+ SoupMessage *message,
+ SoupClientContext *client,
+ gpointer user_data)
+{
+ PathHandler *handler = user_data;
+
+ g_signal_connect (message, "got-headers", G_CALLBACK (got_headers), handler);
+}
+
+static void
server_callback (SoupServer *server, SoupMessage *msg,
const char *path, GHashTable *query,
SoupClientContext *context, gpointer user_data)
@@ -2958,8 +3037,6 @@ server_callback (SoupServer *server, SoupMessage *msg,
else if (msg->method == SOUP_METHOD_GET ||
msg->method == SOUP_METHOD_HEAD)
status = method_get (handler, msg, path, &err);
- else if (msg->method == SOUP_METHOD_PUT)
- status = method_put (handler, msg, path, &err);
else if (msg->method == SOUP_METHOD_PROPFIND)
status = method_propfind (handler, msg, path, &err);
else if (msg->method == SOUP_METHOD_PROPPATCH)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]