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