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-async.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 | /* FIXME |
---|
64 | soup_message_cancel (msg2); |
---|
65 | */ |
---|
66 | } |
---|
67 | |
---|
68 | static void |
---|
69 | finish_msg (SoupMessage *msg2, gpointer msg) |
---|
70 | { |
---|
71 | printf ("[%p] done\n\n", msg); |
---|
72 | g_signal_handlers_disconnect_by_func (msg, client_msg_failed, msg2); |
---|
73 | |
---|
74 | soup_message_add_final_chunk (msg); |
---|
75 | soup_message_io_unpause (msg); |
---|
76 | g_object_unref (msg); |
---|
77 | } |
---|
78 | |
---|
79 | static void |
---|
80 | server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data) |
---|
81 | { |
---|
82 | SoupMessage *msg2; |
---|
83 | char *uristr; |
---|
84 | |
---|
85 | uristr = soup_uri_to_string (soup_message_get_uri (msg), FALSE); |
---|
86 | printf ("[%p] %s %s HTTP/1.%d\n", msg, msg->method, uristr, |
---|
87 | soup_message_get_http_version (msg)); |
---|
88 | |
---|
89 | if (soup_method_get_id (msg->method) == SOUP_METHOD_ID_CONNECT) { |
---|
90 | soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); |
---|
91 | return; |
---|
92 | } |
---|
93 | |
---|
94 | msg2 = soup_message_new (msg->method, uristr); |
---|
95 | soup_message_foreach_header (msg->request_headers, copy_header, |
---|
96 | msg2->request_headers); |
---|
97 | soup_message_remove_header (msg2->request_headers, "Host"); |
---|
98 | soup_message_remove_header (msg2->request_headers, "Connection"); |
---|
99 | |
---|
100 | if (msg->request.length) { |
---|
101 | msg2->request.owner = SOUP_BUFFER_USER_OWNED; |
---|
102 | msg2->request.body = msg->request.body; |
---|
103 | msg2->request.length = msg->request.length; |
---|
104 | } |
---|
105 | soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (msg), |
---|
106 | SOUP_TRANSFER_CHUNKED); |
---|
107 | |
---|
108 | g_signal_connect (msg2, "got_headers", |
---|
109 | G_CALLBACK (send_headers), msg); |
---|
110 | g_signal_connect (msg2, "got_chunk", |
---|
111 | G_CALLBACK (send_chunk), msg); |
---|
112 | soup_message_set_flags (msg2, SOUP_MESSAGE_OVERWRITE_CHUNKS); |
---|
113 | |
---|
114 | g_signal_connect (msg, "finished", G_CALLBACK (client_msg_failed), msg2); |
---|
115 | |
---|
116 | soup_session_queue_message (session, msg2, finish_msg, msg); |
---|
117 | |
---|
118 | g_object_ref (msg); |
---|
119 | soup_message_io_pause (msg); |
---|
120 | } |
---|
121 | |
---|
122 | static void |
---|
123 | quit (int sig) |
---|
124 | { |
---|
125 | /* Exit cleanly on ^C in case we're valgrinding. */ |
---|
126 | exit (0); |
---|
127 | } |
---|
128 | |
---|
129 | int |
---|
130 | main (int argc, char **argv) |
---|
131 | { |
---|
132 | GMainLoop *loop; |
---|
133 | int opt; |
---|
134 | int port = SOUP_ADDRESS_ANY_PORT; |
---|
135 | SoupServer *server; |
---|
136 | |
---|
137 | g_type_init (); |
---|
138 | signal (SIGINT, quit); |
---|
139 | |
---|
140 | while ((opt = getopt (argc, argv, "p:s:")) != -1) { |
---|
141 | switch (opt) { |
---|
142 | case 'p': |
---|
143 | port = atoi (optarg); |
---|
144 | break; |
---|
145 | default: |
---|
146 | fprintf (stderr, "Usage: %s [-p port] [-n]\n", |
---|
147 | argv[0]); |
---|
148 | exit (1); |
---|
149 | } |
---|
150 | } |
---|
151 | |
---|
152 | server = soup_server_new (SOUP_SERVER_PORT, port, |
---|
153 | NULL); |
---|
154 | if (!server) { |
---|
155 | fprintf (stderr, "Unable to bind to server port %d\n", port); |
---|
156 | exit (1); |
---|
157 | } |
---|
158 | soup_server_add_handler (server, NULL, NULL, |
---|
159 | server_callback, NULL, NULL); |
---|
160 | |
---|
161 | printf ("\nStarting proxy on port %d\n", |
---|
162 | soup_server_get_port (server)); |
---|
163 | soup_server_run_async (server); |
---|
164 | |
---|
165 | session = soup_session_async_new (); |
---|
166 | |
---|
167 | printf ("\nWaiting for requests...\n"); |
---|
168 | |
---|
169 | loop = g_main_loop_new (NULL, TRUE); |
---|
170 | g_main_loop_run (loop); |
---|
171 | g_main_loop_unref (loop); |
---|
172 | |
---|
173 | return 0; |
---|
174 | } |
---|