[rygel] core: Separate class for HTTP GET request



commit 29a4b8414b6fc656dc2479fcf3abf3a1d469efb0
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date:   Thu Jan 28 11:41:30 2010 +0200

    core: Separate class for HTTP GET request
    
    More generalization so that we can easily implement request and request
    handler classes for other HTTP methods (e.g POST). This change also
    implies renaming of HTTPRequestHander to HTTPGetHandler.

 src/rygel/Makefile.am                              |    3 +-
 src/rygel/rygel-http-byte-seek.vala                |    4 +-
 ...st-handler.vala => rygel-http-get-handler.vala} |   12 +-
 src/rygel/rygel-http-get.vala                      |  129 ++++++++++++++++++++
 src/rygel/rygel-http-identity-handler.vala         |   10 +-
 src/rygel/rygel-http-request.vala                  |  108 +++--------------
 src/rygel/rygel-http-server.vala                   |    2 +-
 src/rygel/rygel-http-time-seek.vala                |    4 +-
 src/rygel/rygel-http-transcode-handler.vala        |    8 +-
 9 files changed, 170 insertions(+), 110 deletions(-)
---
diff --git a/src/rygel/Makefile.am b/src/rygel/Makefile.am
index 2f72214..50caa70 100644
--- a/src/rygel/Makefile.am
+++ b/src/rygel/Makefile.am
@@ -54,7 +54,8 @@ VAPI_SOURCE_FILES = rygel-configuration.vala \
 		    rygel-http-server.vala \
 		    rygel-state-machine.vala \
 		    rygel-http-request.vala \
-		    rygel-http-request-handler.vala \
+		    rygel-http-get-handler.vala \
+		    rygel-http-get.vala \
 		    rygel-http-identity-handler.vala \
 		    rygel-http-transcode-handler.vala \
 		    rygel-http-seek.vala \
diff --git a/src/rygel/rygel-http-byte-seek.vala b/src/rygel/rygel-http-byte-seek.vala
index a1727dc..ad47dae 100644
--- a/src/rygel/rygel-http-byte-seek.vala
+++ b/src/rygel/rygel-http-byte-seek.vala
@@ -22,7 +22,7 @@
  */
 
 internal class Rygel.HTTPByteSeek : Rygel.HTTPSeek {
-    public HTTPByteSeek (HTTPRequest request) throws HTTPSeekError {
+    public HTTPByteSeek (HTTPGet request) throws HTTPSeekError {
         string range, pos;
         string[] range_tokens;
         int64 start = 0, total_length;
@@ -77,7 +77,7 @@ internal class Rygel.HTTPByteSeek : Rygel.HTTPSeek {
               total_length);
     }
 
-    public static bool needed (HTTPRequest request) {
+    public static bool needed (HTTPGet request) {
         return (request.item.size > 0 &&
                 request.handler is HTTPIdentityHandler) ||
                (request.thumbnail != null && request.thumbnail.size > 0);
diff --git a/src/rygel/rygel-http-request-handler.vala b/src/rygel/rygel-http-get-handler.vala
similarity index 87%
rename from src/rygel/rygel-http-request-handler.vala
rename to src/rygel/rygel-http-get-handler.vala
index f958c22..fe9c354 100644
--- a/src/rygel/rygel-http-request-handler.vala
+++ b/src/rygel/rygel-http-get-handler.vala
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009 Nokia Corporation.
+ * Copyright (C) 2008-2010 Nokia Corporation.
  *
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
  *                               <zeeshan ali nokia com>
@@ -24,13 +24,13 @@
 using GUPnP;
 
 /**
- * HTTP request handler interface.
+ * HTTP GET request handler interface.
  */
-internal abstract class Rygel.HTTPRequestHandler: GLib.Object {
+internal abstract class Rygel.HTTPGetHandler: GLib.Object {
     public Cancellable cancellable { get; set; }
 
     // Add response headers.
-    public virtual void add_response_headers (HTTPRequest request)
+    public virtual void add_response_headers (HTTPGet request)
                                               throws HTTPRequestError {
         var mode = request.msg.request_headers.get ("transferMode.dlna.org");
         if (mode != null) {
@@ -59,10 +59,10 @@ internal abstract class Rygel.HTTPRequestHandler: GLib.Object {
     }
 
     // Create an HTTPResponse object that will render the body.
-    public abstract HTTPResponse render_body (HTTPRequest request)
+    public abstract HTTPResponse render_body (HTTPGet request)
                                               throws HTTPRequestError;
 
     protected abstract DIDLLiteResource add_resource (DIDLLiteItem didl_item,
-                                                      HTTPRequest  request)
+                                                      HTTPGet      request)
                                                       throws Error;
 }
diff --git a/src/rygel/rygel-http-get.vala b/src/rygel/rygel-http-get.vala
new file mode 100644
index 0000000..a3596e5
--- /dev/null
+++ b/src/rygel/rygel-http-get.vala
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008-2010 Nokia Corporation.
+ * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ *                               <zeeshan ali nokia com>
+ *         Jorn Baayen <jorn baayen gmail com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Gst;
+
+/**
+ * Responsible for handling HTTP GET & HEAD client requests.
+ */
+internal class Rygel.HTTPGet : HTTPRequest {
+    public Thumbnail thumbnail;
+    public HTTPSeek seek;
+
+    private int thumbnail_index;
+
+    public HTTPGetHandler handler;
+
+    public HTTPGet (HTTPServer                http_server,
+                    Soup.Server               server,
+                    Soup.Message              msg,
+                    HashTable<string,string>? query) {
+        base (http_server, server, msg, query);
+
+        this.thumbnail_index = -1;
+    }
+
+    protected override async void handle () {
+        this.server.pause_message (this.msg);
+
+        yield base.handle ();
+
+        var header = this.msg.request_headers.get (
+                                        "getcontentFeatures.dlna.org");
+
+        /* We only entertain 'HEAD' and 'GET' requests */
+        if ((this.msg.method != "HEAD" && this.msg.method != "GET") ||
+            (header != null && header != "1")) {
+            this.handle_error (
+                        new HTTPRequestError.BAD_REQUEST ("Invalid Request"));
+            return;
+        }
+
+        try {
+            if (uri.transcode_target != null) {
+                var transcoder = this.http_server.get_transcoder (
+                                                        uri.transcode_target);
+                this.handler = new HTTPTranscodeHandler (transcoder,
+                                                         this.cancellable);
+            }
+        } catch (Error err) {
+            warning ("Failed to parse query: %s", err.message);
+        }
+
+        if (this.handler == null) {
+            this.handler = new HTTPIdentityHandler (this.cancellable);
+        }
+
+        yield this.handle_item_request ();
+    }
+
+    protected override async void find_item () {
+        yield base.find_item ();
+
+        if (this.uri.thumbnail_index >= 0) {
+            this.thumbnail = this.item.thumbnails.get (
+                                        this.uri.thumbnail_index);
+        }
+    }
+
+    private async void handle_item_request () {
+        try {
+            if (HTTPTimeSeek.needed (this)) {
+                this.seek = new HTTPTimeSeek (this);
+            } else if (HTTPByteSeek.needed (this)) {
+                this.seek = new HTTPByteSeek (this);
+            }
+
+            // Add headers
+            this.handler.add_response_headers (this);
+            debug ("Following HTTP headers appended to response:");
+            this.msg.response_headers.foreach ((name, value) => {
+                    debug ("%s : %s", name, value);
+            });
+
+            if (this.msg.method == "HEAD") {
+                // Only headers requested, no need to send contents
+                this.server.unpause_message (this.msg);
+                this.end (Soup.KnownStatusCode.OK);
+                return;
+            }
+
+            var response = this.handler.render_body (this);
+
+            yield response.run ();
+
+            this.end (Soup.KnownStatusCode.NONE);
+        } catch (Error error) {
+            this.handle_error (error);
+        }
+    }
+
+    protected override void handle_error (Error error) {
+        this.server.unpause_message (this.msg);
+
+        base.handle_error (error);
+    }
+}
+
diff --git a/src/rygel/rygel-http-identity-handler.vala b/src/rygel/rygel-http-identity-handler.vala
index 7152d26..9db8625 100644
--- a/src/rygel/rygel-http-identity-handler.vala
+++ b/src/rygel/rygel-http-identity-handler.vala
@@ -24,13 +24,13 @@
 using GUPnP;
 
 // An HTTP request handler that passes the item content through as is.
-internal class Rygel.HTTPIdentityHandler : Rygel.HTTPRequestHandler {
+internal class Rygel.HTTPIdentityHandler : Rygel.HTTPGetHandler {
 
     public HTTPIdentityHandler (Cancellable? cancellable) {
         this.cancellable = cancellable;
     }
 
-    public override void add_response_headers (HTTPRequest request)
+    public override void add_response_headers (HTTPGet request)
                                                throws HTTPRequestError {
         if (request.thumbnail != null) {
             request.msg.response_headers.append ("Content-Type",
@@ -48,7 +48,7 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPRequestHandler {
         base.add_response_headers (request);
     }
 
-    public override HTTPResponse render_body (HTTPRequest request)
+    public override HTTPResponse render_body (HTTPGet request)
                                               throws HTTPRequestError {
         try {
             return this.render_body_real (request);
@@ -58,7 +58,7 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPRequestHandler {
     }
 
     protected override DIDLLiteResource add_resource (DIDLLiteItem didl_item,
-                                                      HTTPRequest  request)
+                                                      HTTPGet      request)
                                                       throws Error {
         var protocol = request.http_server.get_protocol ();
 
@@ -69,7 +69,7 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPRequestHandler {
         }
     }
 
-    private HTTPResponse render_body_real (HTTPRequest request) throws Error {
+    private HTTPResponse render_body_real (HTTPGet request) throws Error {
         if (request.thumbnail != null) {
             return new SeekableResponse (request.server,
                                          request.msg,
diff --git a/src/rygel/rygel-http-request.vala b/src/rygel/rygel-http-request.vala
index 4887b7c..afe1dd9 100644
--- a/src/rygel/rygel-http-request.vala
+++ b/src/rygel/rygel-http-request.vala
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009 Nokia Corporation.
+ * Copyright (C) 2008-2010 Nokia Corporation.
  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd.
  *
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
@@ -23,8 +23,6 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-using Gst;
-
 internal errordomain Rygel.HTTPRequestError {
     UNACCEPTABLE = Soup.KnownStatusCode.NOT_ACCEPTABLE,
     BAD_REQUEST = Soup.KnownStatusCode.BAD_REQUEST,
@@ -32,9 +30,9 @@ internal errordomain Rygel.HTTPRequestError {
 }
 
 /**
- * Responsible for handling HTTP client requests.
+ * Base class for HTTP client requests.
  */
-internal class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine {
+internal abstract class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine {
     public unowned HTTPServer http_server;
     private MediaContainer root_container;
     public Soup.Server server;
@@ -43,13 +41,8 @@ internal class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine {
 
     public Cancellable cancellable { get; set; }
 
-    private string item_id;
-    private int thumbnail_index;
+    protected HTTPItemURI uri;
     public MediaItem item;
-    public Thumbnail thumbnail;
-    public HTTPSeek seek;
-
-    public HTTPRequestHandler handler;
 
     public HTTPRequest (HTTPServer                http_server,
                         Soup.Server               server,
@@ -61,111 +54,49 @@ internal class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine {
         this.server = server;
         this.msg = msg;
         this.query = query;
-        this.thumbnail_index = -1;
     }
 
     public async void run () {
-        this.server.pause_message (this.msg);
-
-        var header = this.msg.request_headers.get (
-                                        "getcontentFeatures.dlna.org");
-
-        /* We only entertain 'HEAD' and 'GET' requests */
-        if ((this.msg.method != "HEAD" && this.msg.method != "GET") ||
-            (header != null && header != "1")) {
-            this.handle_error (
-                        new HTTPRequestError.BAD_REQUEST ("Invalid Request"));
-            return;
-        }
-
-        try {
-            var uri = new HTTPItemURI.from_string (this.msg.uri.path,
-                                                   this.http_server.path_root);
-
-            this.item_id = uri.item_id;
-            this.thumbnail_index = uri.thumbnail_index;
-            if (uri.transcode_target != null) {
-                var transcoder = this.http_server.get_transcoder (
-                                                        uri.transcode_target);
-                this.handler = new HTTPTranscodeHandler (transcoder,
-                                                         this.cancellable);
-            }
-        } catch (Error err) {
-            warning ("Failed to parse query: %s", err.message);
-        }
+        yield this.handle ();
+    }
 
+    protected virtual async void handle () {
+        this.uri = new HTTPItemURI.from_string (this.msg.uri.path,
+                                                this.http_server.path_root);
 
-        if (this.item_id == null) {
+        if (this.uri.item_id == null) {
             this.handle_error (new HTTPRequestError.NOT_FOUND ("Not Found"));
+
             return;
         }
 
-        if (this.handler == null) {
-            this.handler = new HTTPIdentityHandler (this.cancellable);
-        }
         yield this.find_item ();
     }
 
-    public async void find_item () {
+    protected virtual async void find_item () {
         // Fetch the requested item
         MediaObject media_object;
         try {
-            media_object = yield this.root_container.find_object (this.item_id,
-                                                                  null);
+            media_object = yield this.root_container.find_object (
+                                        this.uri.item_id,
+                                        null);
         } catch (Error err) {
             this.handle_error (err);
+
             return;
         }
 
         if (media_object == null || !(media_object is MediaItem)) {
             this.handle_error (new HTTPRequestError.NOT_FOUND (
                                         "requested item '%s' not found",
-                                        this.item_id));
+                                        this.uri.item_id));
             return;
         }
 
         this.item = (MediaItem) media_object;
-
-        if (this.thumbnail_index >= 0) {
-            this.thumbnail = this.item.thumbnails.get (this.thumbnail_index);
-        }
-
-        yield this.handle_item_request ();
-    }
-
-    private async void handle_item_request () {
-        try {
-            if (HTTPTimeSeek.needed (this)) {
-                this.seek = new HTTPTimeSeek (this);
-            } else if (HTTPByteSeek.needed (this)) {
-                this.seek = new HTTPByteSeek (this);
-            }
-
-            // Add headers
-            this.handler.add_response_headers (this);
-            debug ("Following HTTP headers appended to response:");
-            this.msg.response_headers.foreach ((name, value) => {
-                    debug ("%s : %s", name, value);
-            });
-
-            if (this.msg.method == "HEAD") {
-                // Only headers requested, no need to send contents
-                this.server.unpause_message (this.msg);
-                this.end (Soup.KnownStatusCode.OK);
-                return;
-            }
-
-            var response = this.handler.render_body (this);
-
-            yield response.run ();
-
-            this.end (Soup.KnownStatusCode.NONE);
-        } catch (Error error) {
-            this.handle_error (error);
-        }
     }
 
-    private void handle_error (Error error) {
+    protected virtual void handle_error (Error error) {
         warning ("%s", error.message);
 
         uint status;
@@ -175,11 +106,10 @@ internal class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine {
             status = Soup.KnownStatusCode.NOT_FOUND;
         }
 
-        this.server.unpause_message (this.msg);
         this.end (status);
     }
 
-    public void end (uint status) {
+    protected void end (uint status) {
         if (status != Soup.KnownStatusCode.NONE) {
             this.msg.set_status (status);
         }
diff --git a/src/rygel/rygel-http-server.vala b/src/rygel/rygel-http-server.vala
index 33ad342..a0cef18 100644
--- a/src/rygel/rygel-http-server.vala
+++ b/src/rygel/rygel-http-server.vala
@@ -169,7 +169,7 @@ internal class Rygel.HTTPServer : Rygel.TranscodeManager, Rygel.StateMachine {
                 debug ("%s : %s", name, value);
         });
 
-        var request = new HTTPRequest (this, server, msg, query);
+        var request = new HTTPGet (this, server, msg, query);
 
         request.completed += this.on_request_completed;
         this.requests.add (request);
diff --git a/src/rygel/rygel-http-time-seek.vala b/src/rygel/rygel-http-time-seek.vala
index 970bab6..a855f3c 100644
--- a/src/rygel/rygel-http-time-seek.vala
+++ b/src/rygel/rygel-http-time-seek.vala
@@ -31,7 +31,7 @@ internal class Rygel.HTTPTimeSeek : Rygel.HTTPSeek {
     // and not
     //
     // TimeSeekRange.dlna.org : npt=10:19:25.7-13:23:33.6
-    public HTTPTimeSeek (HTTPRequest request) throws HTTPSeekError {
+    public HTTPTimeSeek (HTTPGet request) throws HTTPSeekError {
         string range, time;
         string[] range_tokens;
         int64 start = 0;
@@ -80,7 +80,7 @@ internal class Rygel.HTTPTimeSeek : Rygel.HTTPSeek {
               duration);
     }
 
-    public static bool needed (HTTPRequest request) {
+    public static bool needed (HTTPGet request) {
         return request.item.duration > 0 &&
                (request.handler is HTTPTranscodeHandler ||
                 (request.thumbnail == null &&
diff --git a/src/rygel/rygel-http-transcode-handler.vala b/src/rygel/rygel-http-transcode-handler.vala
index 149e5e0..1b732de 100644
--- a/src/rygel/rygel-http-transcode-handler.vala
+++ b/src/rygel/rygel-http-transcode-handler.vala
@@ -27,7 +27,7 @@ using GUPnP;
 /**
  * The handler for HTTP transcoding requests.
  */
-internal class Rygel.HTTPTranscodeHandler : HTTPRequestHandler {
+internal class Rygel.HTTPTranscodeHandler : HTTPGetHandler {
     private Transcoder transcoder;
 
     public HTTPTranscodeHandler (Transcoder   transcoder,
@@ -36,7 +36,7 @@ internal class Rygel.HTTPTranscodeHandler : HTTPRequestHandler {
         this.cancellable = cancellable;
     }
 
-    public override void add_response_headers (HTTPRequest request)
+    public override void add_response_headers (HTTPGet request)
                                                throws HTTPRequestError {
         request.msg.response_headers.append ("Content-Type",
                                              this.transcoder.mime_type);
@@ -48,7 +48,7 @@ internal class Rygel.HTTPTranscodeHandler : HTTPRequestHandler {
         base.add_response_headers (request);
     }
 
-    public override HTTPResponse render_body (HTTPRequest request)
+    public override HTTPResponse render_body (HTTPGet request)
                                               throws HTTPRequestError {
         var item = request.item;
         var src = item.create_stream_source ();
@@ -71,7 +71,7 @@ internal class Rygel.HTTPTranscodeHandler : HTTPRequestHandler {
     }
 
     protected override DIDLLiteResource add_resource (DIDLLiteItem didl_item,
-                                                      HTTPRequest  request)
+                                                      HTTPGet      request)
                                                       throws Error {
         return this.transcoder.add_resource (didl_item,
                                              request.item,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]