f469d3b0547ab8bf60e9f3d8a23a2d6767bd6cea
[platform/upstream/libsoup.git] / libsoup / soup-message-server-io.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-message-server-io.c: server-side request/response
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "soup-message-private.h"
16 #include "soup-address.h"
17 #include "soup-auth.h"
18 #include "soup-headers.h"
19 #include "soup-misc.h"
20 #include "soup-private.h"
21 #include "soup-server-message.h"
22 #include "soup-server.h"
23 #include "soup-socket.h"
24
25 static guint
26 parse_request_headers (SoupMessage *msg, char *headers, guint headers_len,
27                        SoupTransferEncoding *encoding, guint *content_len,
28                        gpointer sock)
29 {
30         SoupUri *uri;
31         char *req_path = NULL, *url;
32         const char *length, *enc, *req_host;
33         SoupServer *server;
34
35         if (!soup_headers_parse_request (headers, headers_len,
36                                          msg->request_headers,
37                                          (char **) &msg->method,
38                                          &req_path,
39                                          &msg->priv->http_version))
40                 return SOUP_STATUS_BAD_REQUEST;
41
42         /* Handle request body encoding */
43         length = soup_message_get_header (msg->request_headers,
44                                           "Content-Length");
45         enc = soup_message_get_header (msg->request_headers,
46                                        "Transfer-Encoding");
47
48         if (enc) {
49                 if (g_strcasecmp (enc, "chunked") == 0)
50                         *encoding = SOUP_TRANSFER_CHUNKED;
51                 else {
52                         g_warning ("Unknown encoding type in HTTP request.");
53                         g_free (req_path);
54                         return SOUP_STATUS_NOT_IMPLEMENTED;
55                 }
56         } else if (length) {
57                 int len;
58                 *encoding = SOUP_TRANSFER_CONTENT_LENGTH;
59                 len = atoi (length);
60                 if (len < 0) {
61                         g_free (req_path);
62                         return SOUP_STATUS_BAD_REQUEST;
63                 }
64                 *content_len = len;
65         } else {
66                 *encoding = SOUP_TRANSFER_CONTENT_LENGTH;
67                 *content_len = 0;
68         }
69
70         /* Generate correct context for request */
71         server = soup_server_message_get_server (SOUP_SERVER_MESSAGE (msg));
72         req_host = soup_message_get_header (msg->request_headers, "Host");
73
74         if (*req_path != '/') {
75                 /* Check for absolute URI */
76                 SoupUri *absolute;
77
78                 absolute = soup_uri_new (req_path);
79                 if (absolute) {
80                         url = g_strdup (req_path);
81                         soup_uri_free (absolute);
82                 } else {
83                         g_free (req_path);
84                         return SOUP_STATUS_BAD_REQUEST;
85                 }
86         } else if (req_host) {
87                 url = g_strdup_printf ("%s://%s:%d%s",
88                                        soup_server_get_protocol (server) == SOUP_PROTOCOL_HTTPS ? "https" : "http",
89                                        req_host, soup_server_get_port (server),
90                                        req_path);
91         } else if (msg->priv->http_version == SOUP_HTTP_1_0) {
92                 /* No Host header, no AbsoluteUri */
93                 SoupAddress *addr = soup_socket_get_local_address (sock);
94                 const char *host = soup_address_get_physical (addr);
95
96                 url = g_strdup_printf ("%s://%s:%d%s",
97                                        soup_server_get_protocol (server) == SOUP_PROTOCOL_HTTPS ? "https" : "http",
98                                        host, soup_server_get_port (server),
99                                        req_path);
100         } else {
101                 g_free (req_path);
102                 return SOUP_STATUS_BAD_REQUEST;
103         }
104
105         uri = soup_uri_new (url);
106         g_free (url);
107         g_free (req_path);
108
109         if (!uri)
110                 return SOUP_STATUS_BAD_REQUEST;
111
112         soup_message_set_uri (msg, uri);
113         soup_uri_free (uri);
114
115         return SOUP_STATUS_OK;
116 }
117
118 static void
119 write_header (gpointer name, gpointer value, gpointer headers)
120 {
121         g_string_append_printf (headers, "%s: %s\r\n",
122                                 (char *)name, (char *)value);
123 }
124
125 static void
126 get_response_headers (SoupMessage *msg, GString *headers,
127                       SoupTransferEncoding *encoding,
128                       gpointer user_data)
129 {
130         SoupServerMessage *smsg = SOUP_SERVER_MESSAGE (msg);
131
132         g_string_append_printf (headers, "HTTP/1.1 %d %s\r\n",
133                                 msg->status_code, msg->reason_phrase);
134
135         soup_message_foreach_header (msg->response_headers,
136                                      write_header, headers);
137
138         *encoding = soup_server_message_get_encoding (smsg);
139         if (*encoding == SOUP_TRANSFER_CONTENT_LENGTH) {
140                 g_string_append_printf (headers, "Content-Length: %d\r\n",
141                                         msg->response.length);
142         } else if (*encoding == SOUP_TRANSFER_CHUNKED)
143                 g_string_append (headers, "Transfer-Encoding: chunked\r\n");
144
145         g_string_append (headers, "\r\n");
146 }
147
148 void
149 soup_message_read_request (SoupMessage *req, SoupSocket *sock)
150 {
151         soup_message_io_server (req, sock,
152                                 get_response_headers,
153                                 parse_request_headers,
154                                 sock);
155 }