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 | |
---|
22 | static void |
---|
23 | print_header (gpointer name, gpointer value, gpointer data) |
---|
24 | { |
---|
25 | printf ("%s: %s\n", (char *)name, (char *)value); |
---|
26 | } |
---|
27 | |
---|
28 | static void |
---|
29 | server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data) |
---|
30 | { |
---|
31 | char *path, *path_to_open, *slash; |
---|
32 | struct stat st; |
---|
33 | int fd; |
---|
34 | |
---|
35 | path = soup_uri_to_string (soup_message_get_uri (msg), TRUE); |
---|
36 | printf ("%s %s HTTP/1.%d\n", msg->method, path, |
---|
37 | soup_message_get_http_version (msg)); |
---|
38 | soup_message_foreach_header (msg->request_headers, print_header, NULL); |
---|
39 | if (msg->request.length) |
---|
40 | printf ("%.*s\n", msg->request.length, msg->request.body); |
---|
41 | |
---|
42 | if (soup_method_get_id (msg->method) != SOUP_METHOD_ID_GET) { |
---|
43 | soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); |
---|
44 | goto DONE; |
---|
45 | } |
---|
46 | |
---|
47 | if (path) { |
---|
48 | if (*path != '/') { |
---|
49 | soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); |
---|
50 | goto DONE; |
---|
51 | } |
---|
52 | } else |
---|
53 | path = g_strdup (""); |
---|
54 | |
---|
55 | path_to_open = g_strdup_printf (".%s", path); |
---|
56 | |
---|
57 | TRY_AGAIN: |
---|
58 | if (stat (path_to_open, &st) == -1) { |
---|
59 | g_free (path_to_open); |
---|
60 | if (errno == EPERM) |
---|
61 | soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); |
---|
62 | else if (errno == ENOENT) |
---|
63 | soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); |
---|
64 | else |
---|
65 | soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); |
---|
66 | goto DONE; |
---|
67 | } |
---|
68 | |
---|
69 | if (S_ISDIR (st.st_mode)) { |
---|
70 | slash = strrchr (path_to_open, '/'); |
---|
71 | if (!slash || slash[1]) { |
---|
72 | char *uri, *redir_uri; |
---|
73 | |
---|
74 | uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE); |
---|
75 | redir_uri = g_strdup_printf ("%s/", uri); |
---|
76 | soup_message_add_header (msg->response_headers, |
---|
77 | "Location", redir_uri); |
---|
78 | soup_message_set_status (msg, SOUP_STATUS_MOVED_PERMANENTLY); |
---|
79 | g_free (redir_uri); |
---|
80 | g_free (uri); |
---|
81 | g_free (path_to_open); |
---|
82 | goto DONE; |
---|
83 | } |
---|
84 | |
---|
85 | g_free (path_to_open); |
---|
86 | path_to_open = g_strdup_printf (".%s/index.html", path); |
---|
87 | goto TRY_AGAIN; |
---|
88 | } |
---|
89 | |
---|
90 | fd = open (path_to_open, O_RDONLY); |
---|
91 | g_free (path_to_open); |
---|
92 | if (fd == -1) { |
---|
93 | soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); |
---|
94 | goto DONE; |
---|
95 | } |
---|
96 | |
---|
97 | msg->response.owner = SOUP_BUFFER_SYSTEM_OWNED; |
---|
98 | msg->response.length = st.st_size; |
---|
99 | msg->response.body = g_malloc (msg->response.length); |
---|
100 | |
---|
101 | read (fd, msg->response.body, msg->response.length); |
---|
102 | close (fd); |
---|
103 | |
---|
104 | soup_message_set_status (msg, SOUP_STATUS_OK); |
---|
105 | |
---|
106 | DONE: |
---|
107 | g_free (path); |
---|
108 | soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (msg), |
---|
109 | SOUP_TRANSFER_CONTENT_LENGTH); |
---|
110 | printf (" -> %d %s\n\n", msg->status_code, msg->reason_phrase); |
---|
111 | } |
---|
112 | |
---|
113 | static void |
---|
114 | quit (int sig) |
---|
115 | { |
---|
116 | /* Exit cleanly on ^C in case we're valgrinding. */ |
---|
117 | exit (0); |
---|
118 | } |
---|
119 | |
---|
120 | int |
---|
121 | main (int argc, char **argv) |
---|
122 | { |
---|
123 | GMainLoop *loop; |
---|
124 | SoupServer *server, *ssl_server; |
---|
125 | int opt; |
---|
126 | int port = SOUP_ADDRESS_ANY_PORT; |
---|
127 | int ssl_port = SOUP_ADDRESS_ANY_PORT; |
---|
128 | const char *ssl_cert_file = NULL, *ssl_key_file = NULL; |
---|
129 | |
---|
130 | g_type_init (); |
---|
131 | g_thread_init (NULL); |
---|
132 | signal (SIGINT, quit); |
---|
133 | |
---|
134 | while ((opt = getopt (argc, argv, "p:k:c:s:")) != -1) { |
---|
135 | switch (opt) { |
---|
136 | case 'p': |
---|
137 | port = atoi (optarg); |
---|
138 | break; |
---|
139 | case 'k': |
---|
140 | ssl_key_file = optarg; |
---|
141 | break; |
---|
142 | case 'c': |
---|
143 | ssl_cert_file = optarg; |
---|
144 | break; |
---|
145 | case 's': |
---|
146 | ssl_port = atoi (optarg); |
---|
147 | break; |
---|
148 | default: |
---|
149 | fprintf (stderr, "Usage: %s [-p port] [-c ssl-cert-file -k ssl-key-file [-s ssl-port]]\n", |
---|
150 | argv[0]); |
---|
151 | exit (1); |
---|
152 | } |
---|
153 | } |
---|
154 | |
---|
155 | server = soup_server_new (SOUP_SERVER_PORT, port, |
---|
156 | NULL); |
---|
157 | if (!server) { |
---|
158 | fprintf (stderr, "Unable to bind to server port %d\n", port); |
---|
159 | exit (1); |
---|
160 | } |
---|
161 | soup_server_add_handler (server, NULL, NULL, |
---|
162 | server_callback, NULL, NULL); |
---|
163 | printf ("\nStarting Server on port %d\n", |
---|
164 | soup_server_get_port (server)); |
---|
165 | soup_server_run_async (server); |
---|
166 | |
---|
167 | if (ssl_cert_file && ssl_key_file) { |
---|
168 | ssl_server = soup_server_new ( |
---|
169 | SOUP_SERVER_PORT, ssl_port, |
---|
170 | SOUP_SERVER_SSL_CERT_FILE, ssl_cert_file, |
---|
171 | SOUP_SERVER_SSL_KEY_FILE, ssl_key_file, |
---|
172 | NULL); |
---|
173 | |
---|
174 | if (!ssl_server) { |
---|
175 | fprintf (stderr, "Unable to bind to SSL server port %d\n", ssl_port); |
---|
176 | exit (1); |
---|
177 | } |
---|
178 | soup_server_add_handler (ssl_server, NULL, NULL, |
---|
179 | server_callback, NULL, NULL); |
---|
180 | printf ("Starting SSL Server on port %d\n", |
---|
181 | soup_server_get_port (ssl_server)); |
---|
182 | soup_server_run_async (ssl_server); |
---|
183 | } |
---|
184 | |
---|
185 | printf ("\nWaiting for requests...\n"); |
---|
186 | |
---|
187 | loop = g_main_loop_new (NULL, TRUE); |
---|
188 | g_main_loop_run (loop); |
---|
189 | |
---|
190 | return 0; |
---|
191 | } |
---|