Beginnings of improved synchronous API support
[platform/upstream/libsoup.git] / tests / simple-proxy.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2001-2003, Ximian, Inc.
4  */
5
6 #include <ctype.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15
16 #include <glib.h>
17 #include <libsoup/soup-address.h>
18 #include <libsoup/soup-message.h>
19 #include <libsoup/soup-server.h>
20 #include <libsoup/soup-server-message.h>
21 #include <libsoup/soup-session.h>
22
23 /* WARNING: this is really really really not especially compliant with
24  * RFC 2616. But it does work for basic stuff.
25  */
26
27 SoupSession *session;
28
29 static void
30 copy_header (gpointer name, gpointer value, gpointer dest_headers)
31 {
32         soup_message_add_header (dest_headers, name, value);
33 }
34
35 static void
36 send_headers (SoupMessage *from, SoupMessage *to)
37 {
38         printf ("[%p] HTTP/1.%d %d %s\n", to,
39                 soup_message_get_http_version (from),
40                 from->status_code, from->reason_phrase);
41
42         soup_message_set_status_full (to, from->status_code,
43                                       from->reason_phrase);
44         soup_message_foreach_header (from->response_headers, copy_header,
45                                      to->response_headers);
46         soup_message_remove_header (to->response_headers, "Content-Length");
47         soup_message_io_unpause (to);
48 }
49
50 static void
51 send_chunk (SoupMessage *from, SoupMessage *to)
52 {
53         printf ("[%p]   writing chunk of %d bytes\n", to, from->response.length);
54
55         soup_message_add_chunk (to, SOUP_BUFFER_USER_OWNED,
56                                 from->response.body, from->response.length);
57         soup_message_io_unpause (to);
58 }
59
60 static void
61 client_msg_failed (SoupMessage *msg, gpointer msg2)
62 {
63         soup_message_cancel (msg2);
64 }
65
66 static void
67 finish_msg (SoupMessage *msg2, gpointer msg)
68 {
69         printf ("[%p]   done\n\n", msg);
70         g_signal_handlers_disconnect_by_func (msg, client_msg_failed, msg2);
71
72         soup_message_add_final_chunk (msg);
73         soup_message_io_unpause (msg);
74         g_object_unref (msg);
75 }
76
77 static void
78 server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
79 {
80         SoupMessage *msg2;
81         char *uristr;
82
83         uristr = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
84         printf ("[%p] %s %s HTTP/1.%d\n", msg, msg->method, uristr,
85                 soup_message_get_http_version (msg));
86
87         if (soup_method_get_id (msg->method) == SOUP_METHOD_ID_CONNECT) {
88                 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
89                 return;
90         }
91
92         msg2 = soup_message_new (msg->method, uristr);
93         soup_message_foreach_header (msg->request_headers, copy_header,
94                                      msg2->request_headers);
95         soup_message_remove_header (msg2->request_headers, "Host");
96         soup_message_remove_header (msg2->request_headers, "Connection");
97
98         if (msg->request.length) {
99                 msg2->request.owner = SOUP_BUFFER_USER_OWNED;
100                 msg2->request.body = msg->request.body;
101                 msg2->request.length = msg->request.length;
102         }
103         soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (msg),
104                                           SOUP_TRANSFER_CHUNKED);
105
106         g_signal_connect (msg2, "got_headers",
107                           G_CALLBACK (send_headers), msg);
108         g_signal_connect (msg2, "got_chunk",
109                           G_CALLBACK (send_chunk), msg);
110         soup_message_set_flags (msg2, SOUP_MESSAGE_OVERWRITE_CHUNKS);
111
112         g_signal_connect (msg, "finished", G_CALLBACK (client_msg_failed), msg2);
113
114         soup_session_queue_message (session, msg2, finish_msg, msg);
115
116         g_object_ref (msg);
117         soup_message_io_pause (msg);
118 }
119
120 static void
121 quit (int sig)
122 {
123         /* Exit cleanly on ^C in case we're valgrinding. */
124         exit (0);
125 }
126
127 int
128 main (int argc, char **argv)
129 {
130         GMainLoop *loop;
131         int opt;
132         int port = SOUP_ADDRESS_ANY_PORT;
133         SoupServer *server;
134
135         g_type_init ();
136         signal (SIGINT, quit);
137
138         while ((opt = getopt (argc, argv, "p:s:")) != -1) {
139                 switch (opt) {
140                 case 'p':
141                         port = atoi (optarg);
142                         break;
143                 default:
144                         fprintf (stderr, "Usage: %s [-p port] [-n]\n",
145                                  argv[0]);
146                         exit (1);
147                 }
148         }
149
150         server = soup_server_new (SOUP_PROTOCOL_HTTP, port);
151         if (!server) {
152                 fprintf (stderr, "Unable to bind to server port %d\n", port);
153                 exit (1);
154         }
155         soup_server_add_handler (server, NULL, NULL,
156                                  server_callback, NULL, NULL);
157
158         printf ("\nStarting proxy on port %d\n",
159                 soup_server_get_port (server));
160         soup_server_run_async (server);
161
162         session = soup_session_new_default ();
163
164         printf ("\nWaiting for requests...\n");
165
166         loop = g_main_loop_new (NULL, TRUE);
167         g_main_loop_run (loop);
168         g_main_loop_unref (loop);
169
170         return 0;
171 }