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 \
*/
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;
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);
/*
- * Copyright (C) 2008, 2009 Nokia Corporation.
+ * Copyright (C) 2008-2010 Nokia Corporation.
*
* Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
* <zeeshan.ali@nokia.com>
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) {
}
// 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;
}
--- /dev/null
+/*
+ * 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);
+ }
+}
+
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",
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);
}
protected override DIDLLiteResource add_resource (DIDLLiteItem didl_item,
- HTTPRequest request)
+ HTTPGet request)
throws Error {
var protocol = request.http_server.get_protocol ();
}
}
- 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,
/*
- * 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>
* 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,
}
/**
- * 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;
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,
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;
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);
}
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);
// 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;
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 &&
/**
* The handler for HTTP transcoding requests.
*/
-internal class Rygel.HTTPTranscodeHandler : HTTPRequestHandler {
+internal class Rygel.HTTPTranscodeHandler : HTTPGetHandler {
private Transcoder transcoder;
public HTTPTranscodeHandler (Transcoder transcoder,
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);
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 ();
}
protected override DIDLLiteResource add_resource (DIDLLiteItem didl_item,
- HTTPRequest request)
+ HTTPGet request)
throws Error {
return this.transcoder.add_resource (didl_item,
request.item,