2 * Copyright (C) 2010 Nokia Corporation.
4 * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
5 * <zeeshan.ali@nokia.com>
7 * This file is part of Rygel.
9 * Rygel is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * Rygel is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 // This module contains the common code between the test cases for
25 // HTTPResponse subclasses.
28 public errordomain Rygel.TestError {
33 public abstract class Rygel.HTTPResponseTest : GLib.Object {
34 public const long MAX_BYTES = 1024;
36 protected HTTPServer server;
37 protected HTTPClient client;
39 private bool server_done;
40 private bool client_done;
42 private MainLoop main_loop;
44 protected Cancellable cancellable;
47 public HTTPResponseTest (Cancellable? cancellable = null) throws Error {
48 this.cancellable = cancellable;
50 this.server = new HTTPServer ();
51 this.client = new HTTPClient (this.server.context,
55 this.main_loop = new MainLoop (null, false);
58 public HTTPResponseTest.complete () throws Error {
62 public HTTPResponseTest.abort () throws Error {
63 this (new Cancellable ());
66 public virtual void run () throws Error {
67 Timeout.add_seconds (3, this.on_timeout);
68 this.server.message_received.connect (this.on_message_received);
69 this.server.message_aborted.connect (this.on_message_aborted);
70 if (this.cancellable == null) {
71 this.client.completed.connect (this.on_client_completed);
73 this.client_done = true;
76 this.client.run.begin ();
78 this.main_loop.run ();
80 if (this.error != null) {
85 internal abstract HTTPResponse create_response (Soup.Message msg)
88 private void on_client_completed (StateMachine client) {
89 if (this.server_done) {
90 this.main_loop.quit ();
93 this.client_done = true;
96 private void on_response_completed (StateMachine response) {
97 if (this.client_done) {
98 this.main_loop.quit ();
101 this.server_done = true;
104 private void on_message_received (HTTPServer server,
107 var response = this.create_response (msg);
109 response.run.begin ();
111 response.completed.connect (this.on_response_completed);
112 } catch (Error error) {
114 this.main_loop.quit ();
120 private void on_message_aborted (HTTPServer server,
122 this.cancellable.cancel ();
125 private bool on_timeout () {
126 this.error = new TestError.TIMEOUT ("Timeout");
127 this.main_loop.quit ();
133 public class Rygel.HTTPServer : GLib.Object {
134 private const string SERVER_PATH = "/RygelHTTPServer/Rygel/Test";
136 public GUPnP.Context context;
139 owned get { return "http://" +
140 this.context.host_ip + ":" +
141 this.context.port.to_string () +
146 public signal void message_received (Soup.Message message);
147 public signal void message_aborted (Soup.Message message);
149 public HTTPServer () throws TestError {
151 this.context = new GUPnP.Context (null, "lo", 0);
152 } catch (Error error) {
153 throw new TestError.SKIP ("Network context not available");
156 assert (this.context != null);
157 assert (this.context.host_ip != null);
158 assert (this.context.port > 0);
160 this.context.server.add_handler (SERVER_PATH, this.server_cb);
161 this.context.server.request_aborted.connect (this.on_request_aborted);
164 private void server_cb (Server server,
168 ClientContext client) {
169 this.context.server.pause_message (msg);
170 this.message_received (msg);
173 private void on_request_aborted (Soup.Server server,
174 Soup.Message message,
175 Soup.ClientContext client) {
176 this.message_aborted (message);
180 public class Rygel.HTTPClient : GLib.Object, StateMachine {
181 public GUPnP.Context context;
182 public Soup.Message msg;
183 public size_t total_bytes;
185 public Cancellable cancellable { get; set; }
187 public HTTPClient (GUPnP.Context context,
191 this.context = context;
192 this.total_bytes = total_bytes;
194 this.msg = new Soup.Message ("HTTP", uri);
195 assert (this.msg != null);
196 this.msg.response_body.set_accumulate (false);
199 this.cancellable = new Cancellable ();
200 this.cancellable.cancelled += this.on_cancelled;
204 public async void run () {
205 SourceFunc run_continue = run.callback;
206 size_t bytes_received = 0;
208 this.msg.got_chunk.connect ((msg, chunk) => {
209 bytes_received += chunk.length;
211 if (bytes_received >= this.total_bytes &&
212 this.cancellable != null) {
213 bytes_received = bytes_received.clamp (0, this.total_bytes);
215 this.cancellable.cancel ();
219 this.context.session.queue_message (this.msg, (session, msg) => {
220 assert (cancellable == null || bytes_received == this.total_bytes);
230 private void on_cancelled (Cancellable cancellable) {
231 this.context.session.cancel_message (this.msg,
232 KnownStatusCode.CANCELLED);