cc3da2b6c93f1b77fc8f3fefaa082719e6fcf772
[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-session-async.h>
21
22 /* WARNING: this is really really really not especially compliant with
23  * RFC 2616. But it does work for basic stuff.
24  */
25
26 SoupSession *session;
27 SoupServer *server;
28
29 static void
30 copy_header (const char *name, const char *value, gpointer dest_headers)
31 {
32         soup_message_headers_append (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_headers_foreach (from->response_headers, copy_header,
45                                       to->response_headers);
46         soup_message_headers_remove (to->response_headers, "Content-Length");
47         soup_server_unpause_message (server, to);
48 }
49
50 static void
51 send_chunk (SoupMessage *from, SoupBuffer *chunk, SoupMessage *to)
52 {
53         printf ("[%p]   writing chunk of %lu bytes\n", to,
54                 (unsigned long)chunk->length);
55
56         soup_message_body_append_buffer (to->response_body, chunk);
57         soup_server_unpause_message (server, to);
58 }
59
60 static void
61 client_msg_failed (SoupMessage *msg, gpointer msg2)
62 {
63         soup_session_cancel_message (session, msg2, SOUP_STATUS_IO_ERROR);
64 }
65
66 static void
67 finish_msg (SoupSession *session, SoupMessage *msg2, gpointer data)
68 {
69         SoupMessage *msg = data;
70
71         printf ("[%p]   done\n\n", msg);
72         g_signal_handlers_disconnect_by_func (msg, client_msg_failed, msg2);
73
74         soup_message_body_complete (msg->response_body);
75         soup_server_unpause_message (server, msg);
76         g_object_unref (msg);
77 }
78
79 static void
80 server_callback (SoupServer *server, SoupMessage *msg,
81                  const char *path, GHashTable *query,
82                  SoupClientContext *context, gpointer data)
83 {
84         SoupMessage *msg2;
85         char *uristr;
86
87         uristr = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
88         printf ("[%p] %s %s HTTP/1.%d\n", msg, msg->method, uristr,
89                 soup_message_get_http_version (msg));
90
91         if (msg->method == SOUP_METHOD_CONNECT) {
92                 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
93                 return;
94         }
95
96         msg2 = soup_message_new (msg->method, uristr);
97         msg2 = soup_message_new (msg->method, uristr);
98         soup_message_headers_foreach (msg->request_headers, copy_header,
99                                       msg2->request_headers);
100         soup_message_headers_remove (msg2->request_headers, "Host");
101         soup_message_headers_remove (msg2->request_headers, "Connection");
102
103         if (msg->request_body->length) {
104                 SoupBuffer *request = soup_message_body_flatten (msg->request_body);
105                 soup_message_body_append_buffer (msg2->request_body, request);
106                 soup_buffer_free (request);
107         }
108         soup_message_headers_set_encoding (msg->response_headers,
109                                            SOUP_ENCODING_CHUNKED);
110
111         g_signal_connect (msg2, "got_headers",
112                           G_CALLBACK (send_headers), msg);
113         g_signal_connect (msg2, "got_chunk",
114                           G_CALLBACK (send_chunk), msg);
115
116         g_signal_connect (msg, "finished", G_CALLBACK (client_msg_failed), msg2);
117
118         soup_session_queue_message (session, msg2, finish_msg, msg);
119
120         g_object_ref (msg);
121         soup_server_pause_message (server, msg);
122 }
123
124 static void
125 quit (int sig)
126 {
127         /* Exit cleanly on ^C in case we're valgrinding. */
128         exit (0);
129 }
130
131 int
132 main (int argc, char **argv)
133 {
134         GMainLoop *loop;
135         int opt;
136         int port = SOUP_ADDRESS_ANY_PORT;
137
138         g_type_init ();
139         g_thread_init (NULL);
140         signal (SIGINT, quit);
141
142         while ((opt = getopt (argc, argv, "p:s:")) != -1) {
143                 switch (opt) {
144                 case 'p':
145                         port = atoi (optarg);
146                         break;
147                 default:
148                         fprintf (stderr, "Usage: %s [-p port] [-n]\n",
149                                  argv[0]);
150                         exit (1);
151                 }
152         }
153
154         server = soup_server_new (SOUP_SERVER_PORT, port,
155                                   NULL);
156         if (!server) {
157                 fprintf (stderr, "Unable to bind to server port %d\n", port);
158                 exit (1);
159         }
160         soup_server_add_handler (server, NULL,
161                                  server_callback, NULL, NULL);
162
163         printf ("\nStarting proxy on port %d\n",
164                 soup_server_get_port (server));
165         soup_server_run_async (server);
166
167         session = soup_session_async_new ();
168
169         printf ("\nWaiting for requests...\n");
170
171         loop = g_main_loop_new (NULL, TRUE);
172         g_main_loop_run (loop);
173         g_main_loop_unref (loop);
174
175         return 0;
176 }