1 /*
2  * librest - RESTful web services access
3  * Copyright (c) 2010 Intel Corporation.
4  *
5  * Authors: Rob Bradford <rob@linux.intel.com>
6  *          Ross Burton <ross@linux.intel.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU Lesser General Public License,
10  * version 2.1, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT ANY
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22 
23 #include <config.h>
24 
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <libsoup/soup.h>
29 #include <rest/rest-proxy.h>
30 
31 static int errors = 0;
32 static GMainLoop *loop = NULL;
33 
34 #define NUM_CHUNKS 20
35 #define SIZE_CHUNK 4
36 static guint8 server_count = 0;
37 static guint8 client_count = 0;
38 static SoupServer *server;
39 
40 static gboolean
send_chunks(gpointer user_data)41 send_chunks (gpointer user_data)
42 {
43   SoupMessage *msg = SOUP_MESSAGE (user_data);
44   guint i;
45   guint8 data[SIZE_CHUNK];
46 
47   for (i = 0; i < SIZE_CHUNK; i++)
48   {
49     data[i] = server_count;
50     server_count++;
51   }
52 
53   soup_message_body_append (msg->response_body, SOUP_MEMORY_COPY, data, SIZE_CHUNK);
54   soup_server_unpause_message (server, msg);
55 
56   if (server_count == NUM_CHUNKS * SIZE_CHUNK)
57   {
58     soup_message_body_complete (msg->response_body);
59     return FALSE;
60   } else {
61     return TRUE;
62   }
63 }
64 
65 static void
server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * client,gpointer user_data)66 server_callback (SoupServer *server, SoupMessage *msg,
67                  const char *path, GHashTable *query,
68                  SoupClientContext *client, gpointer user_data)
69 {
70   if (g_str_equal (path, "/stream")) {
71     soup_message_set_status (msg, SOUP_STATUS_OK);
72     soup_message_headers_set_encoding (msg->response_headers,
73                                        SOUP_ENCODING_CHUNKED);
74     soup_server_pause_message (server, msg);
75 
76     g_idle_add (send_chunks, msg);
77   }
78 }
79 
80 static void
_call_continuous_cb(RestProxyCall * call,const gchar * buf,gsize len,const GError * error,GObject * weak_object,gpointer userdata)81 _call_continuous_cb (RestProxyCall *call,
82                      const gchar   *buf,
83                      gsize          len,
84                      const GError  *error,
85                      GObject       *weak_object,
86                      gpointer       userdata)
87 {
88   guint i;
89 
90   if (error)
91   {
92     g_printerr ("Error: %s\n", error->message);
93     errors++;
94     goto out;
95   }
96 
97   if (!REST_IS_PROXY (weak_object))
98   {
99     g_printerr ("weak object not as expected\n");
100     errors++;
101     goto out;
102   }
103 
104   if (buf == NULL && len == 0)
105   {
106     if (client_count < NUM_CHUNKS * SIZE_CHUNK)
107     {
108       g_printerr ("stream ended prematurely\n");
109       errors++;
110     }
111     goto out;
112   }
113 
114   for (i = 0; i < len; i++)
115   {
116     if (buf[i] != client_count)
117     {
118       g_printerr ("stream data not as expected (got %d, expected %d)\n",
119                   (gint) buf[i], client_count);
120       errors++;
121       goto out;
122     }
123 
124     client_count++;
125   }
126 
127   return;
128 out:
129   g_main_loop_quit (loop);
130   return;
131 }
132 
133 static void
stream_test(RestProxy * proxy)134 stream_test (RestProxy *proxy)
135 {
136   RestProxyCall *call;
137   GError *error = NULL;
138 
139   call = rest_proxy_new_call (proxy);
140   rest_proxy_call_set_function (call, "stream");
141 
142   if (!rest_proxy_call_continuous (call,
143                                    _call_continuous_cb,
144                                    (GObject *)proxy,
145                                    NULL,
146                                    &error))
147   {
148     g_printerr ("Making stream failed: %s", error->message);
149     g_error_free (error);
150     errors++;
151     return;
152   }
153 
154   g_object_unref (call);
155 }
156 
157 int
main(int argc,char ** argv)158 main (int argc, char **argv)
159 {
160   char *url;
161   RestProxy *proxy;
162 
163 #if !GLIB_CHECK_VERSION (2, 36, 0)
164   g_type_init ();
165 #endif
166   loop = g_main_loop_new (NULL, FALSE);
167 
168   server = soup_server_new (NULL);
169   soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
170   soup_server_run_async (server);
171 
172   url = g_strdup_printf ("http://127.0.0.1:%d/", soup_server_get_port (server));
173   proxy = rest_proxy_new (url, FALSE);
174   g_free (url);
175 
176   stream_test (proxy);
177   g_main_loop_run (loop);
178 
179   return errors != 0;
180 }
181