summaryrefslogtreecommitdiff
path: root/src/librygel-server/rygel-http-resource-handler.vala
blob: af6012b55e288c6df6483b2a481d76fea40b7288 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 * Copyright (C) 2013  Cable Television Laboratories, Inc.
 *
 * Author: Craig Pratt <craig@ecaspia.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.1 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

using GUPnP;

/**
 * The HTTP handler for HTTP ContentResource requests.
 */
internal class Rygel.HTTPMediaResourceHandler : HTTPGetHandler {
    private MediaObject media_object;
    private string media_resource_name;
    public MediaResource media_resource;

    public HTTPMediaResourceHandler (MediaObject media_object,
                                     string media_resource_name,
                                     Cancellable? cancellable)
                                     throws HTTPRequestError {
        this.media_object = media_object;
        this.cancellable = cancellable;
        this.media_resource_name = media_resource_name;
        var resource = media_object.get_resource_by_name (media_resource_name);

        if (resource == null) {
            throw new HTTPRequestError.NOT_FOUND ("MediaResource %s not found",
                                                  media_resource_name);
        }

        // Handler modifies the resource, so we copy it.
        this.media_resource = resource.dup ();
    }

    public override void add_response_headers (HTTPGet request)
                                               throws HTTPRequestError {
        request.http_server.set_resource_delivery_options (this.media_resource);
        var replacements = request.http_server.get_replacements ();
        var mime_type = MediaObject.apply_replacements
                                     (replacements,
                                      this.media_resource.mime_type);
        request.msg.response_headers.append ("Content-Type", mime_type);

        // Add contentFeatures.dlna.org
        var protocol_info = media_resource.get_protocol_info (replacements);
        if (protocol_info != null) {
            var pi_fields = protocol_info.to_string ().split (":", 4);
            if (pi_fields != null && pi_fields[3] != null) {
                request.msg.response_headers.append ("contentFeatures.dlna.org",
                                                     pi_fields[3]);
            }
        }

        // Chain-up
        base.add_response_headers (request);
    }

    public override string get_default_transfer_mode () {
        // Per DLNA 7.5.4.3.2.33.2, the assumed transfer mode is based on the content type
        // "Streaming" for AV content and "Interactive" for all others
        return media_resource.get_default_transfer_mode ();
    }

    public override bool supports_transfer_mode (string mode) {
        return media_resource.supports_transfer_mode (mode);
    }

    public override HTTPResponse render_body (HTTPGet request)
                                              throws HTTPRequestError {
        try {
            var src = request.object.create_stream_source_for_resource
                                    (request, this.media_resource);
            if (src == null) {
                throw new HTTPRequestError.NOT_FOUND
                              (_("Couldn’t create data source for %s"),
                               this.media_resource.get_name ());
            }

            return new HTTPResponse (request, this, src);
        } catch (Error err) {
            throw new HTTPRequestError.NOT_FOUND (err.message);
        }
    }

    public override int64 get_resource_size () {
        return media_resource.size;
    }

    public override int64 get_resource_duration () {
        return media_resource.duration * TimeSpan.SECOND;
    }

    public override bool supports_byte_seek () {
        return media_resource.supports_arbitrary_byte_seek ()
               || media_resource.supports_limited_byte_seek ();
    }

    public override bool supports_time_seek () {
        return media_resource.supports_arbitrary_time_seek ()
               || media_resource.supports_limited_time_seek ();
    }

    public override bool supports_playspeed () {
        return media_resource.supports_playspeed ();
    }
}