1 /*
2  * Copyright (C) 2012 Nokia.
3  *
4  * Author: Jens Georg <jensg@openismus.com>
5  *
6  * SPDX-License-Identifier: LGPL-2.1-or-later
7  */
8 
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12 
13 #include <string.h>
14 
15 #include <libsoup/soup.h>
16 #include "libgupnp/gupnp.h"
17 
18 static GUPnPContext *
create_context(guint16 port,GError ** error)19 create_context (guint16 port, GError **error) {
20         return GUPNP_CONTEXT (g_initable_new (GUPNP_TYPE_CONTEXT,
21                                               NULL,
22                                               error,
23                                               "host-ip", "127.0.0.1",
24                                               "msearch-port", port,
25                                               NULL));
26 }
27 
28 static void
on_message_finished(G_GNUC_UNUSED SoupSession * session,G_GNUC_UNUSED SoupMessage * message,gpointer user_data)29 on_message_finished (G_GNUC_UNUSED SoupSession *session,
30                      G_GNUC_UNUSED SoupMessage *message,
31                      gpointer                   user_data) {
32         GMainLoop *loop = (GMainLoop*) user_data;
33 
34         g_main_loop_quit (loop);
35 }
36 
37 static void
request_range_and_compare(GMappedFile * file,SoupSession * session,GMainLoop * loop,const char * uri,goffset want_start,goffset want_end)38 request_range_and_compare (GMappedFile *file,
39                            SoupSession *session,
40                            GMainLoop   *loop,
41                            const char  *uri,
42                            goffset      want_start,
43                            goffset      want_end)
44 {
45         SoupMessage *message = NULL;
46         goffset      want_length = 0, full_length = 0;
47         goffset      got_start = 0, got_end = 0, got_length = 0;
48         int          result = 0;
49 
50         full_length = g_mapped_file_get_length (file);
51 
52         message = soup_message_new ("GET", uri);
53         g_object_ref (message);
54 
55         soup_message_headers_set_range (message->request_headers,
56                                         want_start,
57                                         want_end);
58 
59         /* interpretation according to SoupRange documentation */
60         if (want_end == -1) {
61                 if (want_start < 0) {
62                         want_length = -want_start;
63                         want_start = full_length + want_start;
64                         want_end = want_start + want_length - 1;
65                 }
66                 else {
67                         want_length = full_length - want_start;
68                         want_end = full_length - 1;
69                 }
70         } else
71                 want_length = want_end - want_start + 1;
72 
73 
74         soup_session_queue_message (session,
75                                     message,
76                                     on_message_finished,
77                                     loop);
78 
79         g_main_loop_run (loop);
80         g_assert_cmpint (message->status_code, ==, SOUP_STATUS_PARTIAL_CONTENT);
81         g_assert_cmpint (message->response_body->length, ==, want_length);
82         got_length = soup_message_headers_get_content_length
83                                         (message->response_headers);
84         g_assert_cmpint (got_length, ==, want_length);
85         soup_message_headers_get_content_range (message->response_headers,
86                                                 &got_start,
87                                                 &got_end,
88                                                 &got_length);
89         g_assert_cmpint (got_start, ==, want_start);
90         g_assert_cmpint (got_end, ==, want_end);
91         result = memcmp (g_mapped_file_get_contents (file) + want_start,
92                          message->response_body->data,
93                          want_length);
94         g_assert_cmpint (result, ==, 0);
95 
96         g_object_unref (message);
97 
98         message = soup_message_new ("GET", uri);
99         g_object_ref (message);
100 }
101 
102 static void
test_gupnp_context_http_ranged_requests(void)103 test_gupnp_context_http_ranged_requests (void)
104 {
105         GUPnPContext *context = NULL;
106         GError *error = NULL;
107         SoupSession *session = NULL;
108         SoupMessage *message = NULL;
109         guint port = 0;
110         char *uri = NULL;
111         GMainLoop *loop;
112         GMappedFile *file;
113         goffset file_length = 0;
114 
115         loop = g_main_loop_new (NULL, FALSE);
116         g_assert (loop != NULL);
117 
118         file = g_mapped_file_new (DATA_PATH "/random4k.bin",
119                                   FALSE,
120                                   &error);
121         g_assert (file != NULL);
122         g_assert (error == NULL);
123         file_length = g_mapped_file_get_length (file);
124 
125         context = create_context (0, &error);
126         g_assert (context != NULL);
127         g_assert (error == NULL);
128         port = gupnp_context_get_port (context);
129 
130         gupnp_context_host_path (context,
131                                  DATA_PATH "/random4k.bin",
132                                  "/random4k.bin");
133 
134         uri = g_strdup_printf ("http://127.0.0.1:%u/random4k.bin", port);
135         g_assert (uri != NULL);
136 
137         session = soup_session_new ();
138 
139         /* Corner cases: First byte */
140         request_range_and_compare (file, session, loop, uri, 0, 0);
141 
142         /* Corner cases: Last byte */
143         request_range_and_compare (file,
144                                    session,
145                                    loop,
146                                    uri,
147                                    file_length - 1,
148                                    file_length - 1);
149 
150         /* Examples from http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html */
151         /* Request first 500 bytes */
152         request_range_and_compare (file, session, loop, uri, 0, 499);
153 
154         /* Request second 500 bytes */
155         request_range_and_compare (file, session, loop, uri, 500, 999);
156 
157         /* Request everything but the first 500 bytes */
158         request_range_and_compare (file, session, loop, uri, 500, file_length - 1);
159 
160         /* Request the last 500 bytes */
161         request_range_and_compare (file, session, loop, uri, file_length - 500, file_length - 1);
162 
163         /* Request the last 500 bytes by using negative requests: Range:
164          * bytes: -500 */
165         request_range_and_compare (file, session, loop, uri, -500, -1);
166 
167         /* Request the last 1k bytes by using negative requests: Range:
168          * bytes: 3072- */
169         request_range_and_compare (file, session, loop, uri, 3072, -1);
170 
171         /* Try to get 1 byte after the end of the file */
172         message = soup_message_new ("GET", uri);
173         g_object_ref (message);
174 
175         soup_message_headers_set_range (message->request_headers,
176                                         file_length,
177                                         file_length);
178         soup_session_queue_message (session,
179                                     message,
180                                     on_message_finished,
181                                     loop);
182 
183         g_main_loop_run (loop);
184         g_assert_cmpint (message->status_code, ==, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
185 
186         g_object_unref (message);
187 
188         g_free (uri);
189         g_object_unref (context);
190         g_main_loop_unref (loop);
191         g_mapped_file_unref (file);
192 }
193 
main(int argc,char * argv[])194 int main (int argc, char *argv[]) {
195         g_test_init (&argc, &argv, NULL);
196         g_test_add_func ("/context/http/ranged-requests",
197                          test_gupnp_context_http_ranged_requests);
198 
199         g_test_run ();
200 
201         return 0;
202 }
203