1 /*
2 HTTP session handling
3 Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
4 Portions are:
5 Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with this library; if not, write to the Free
19 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 MA 02111-1307, USA
21
22 */
23
24 #include "config.h"
25
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #endif
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #ifdef HAVE_ERRNO_H
33 #include <errno.h>
34 #endif
35
36 #include "ne_session.h"
37 #include "ne_alloc.h"
38 #include "ne_utils.h"
39 #include "ne_i18n.h"
40 #include "ne_string.h"
41
42 #include "ne_private.h"
43
44 /* Destroy a a list of hooks. */
destroy_hooks(struct hook * hooks)45 static void destroy_hooks(struct hook *hooks)
46 {
47 struct hook *nexthk;
48
49 while (hooks) {
50 nexthk = hooks->next;
51 ne_free(hooks);
52 hooks = nexthk;
53 }
54 }
55
ne_session_destroy(ne_session * sess)56 void ne_session_destroy(ne_session *sess)
57 {
58 struct hook *hk;
59
60 NE_DEBUG(NE_DBG_HTTP, "ne_session_destroy called.\n");
61
62 /* Run the destroy hooks. */
63 for (hk = sess->destroy_sess_hooks; hk != NULL; hk = hk->next) {
64 ne_destroy_sess_fn fn = (ne_destroy_sess_fn)hk->fn;
65 fn(hk->userdata);
66 }
67
68 destroy_hooks(sess->create_req_hooks);
69 destroy_hooks(sess->pre_send_hooks);
70 destroy_hooks(sess->post_send_hooks);
71 destroy_hooks(sess->destroy_req_hooks);
72 destroy_hooks(sess->destroy_sess_hooks);
73 destroy_hooks(sess->private);
74
75 ne_free(sess->scheme);
76 ne_free(sess->server.hostname);
77 ne_free(sess->server.hostport);
78 if (sess->server.address) ne_addr_destroy(sess->server.address);
79 if (sess->proxy.address) ne_addr_destroy(sess->proxy.address);
80 if (sess->proxy.hostname) ne_free(sess->proxy.hostname);
81 if (sess->user_agent) ne_free(sess->user_agent);
82
83 if (sess->connected) {
84 ne_close_connection(sess);
85 }
86
87 #ifdef NEON_SSL
88 if (sess->ssl_context)
89 ne_ssl_context_destroy(sess->ssl_context);
90
91 if (sess->server_cert)
92 ne_ssl_cert_free(sess->server_cert);
93
94 if (sess->client_cert)
95 ne_ssl_clicert_free(sess->client_cert);
96 #endif
97
98 ne_free(sess);
99 }
100
ne_version_pre_http11(ne_session * s)101 int ne_version_pre_http11(ne_session *s)
102 {
103 return !s->is_http11;
104 }
105
106 /* Stores the "hostname[:port]" segment */
set_hostport(struct host_info * host,unsigned int defaultport)107 static void set_hostport(struct host_info *host, unsigned int defaultport)
108 {
109 size_t len = strlen(host->hostname);
110 host->hostport = ne_malloc(len + 10);
111 strcpy(host->hostport, host->hostname);
112 if (host->port != defaultport)
113 ne_snprintf(host->hostport + len, 9, ":%u", host->port);
114 }
115
116 /* Stores the hostname/port in *info, setting up the "hostport"
117 * segment correctly. */
118 static void
set_hostinfo(struct host_info * info,const char * hostname,unsigned int port)119 set_hostinfo(struct host_info *info, const char *hostname, unsigned int port)
120 {
121 info->hostname = ne_strdup(hostname);
122 info->port = port;
123 }
124
ne_session_create(const char * scheme,const char * hostname,unsigned int port)125 ne_session *ne_session_create(const char *scheme,
126 const char *hostname, unsigned int port)
127 {
128 ne_session *sess = ne_calloc(sizeof *sess);
129
130 NE_DEBUG(NE_DBG_HTTP, "HTTP session to %s://%s:%d begins.\n",
131 scheme, hostname, port);
132
133 strcpy(sess->error, "Unknown error.");
134
135 /* use SSL if scheme is https */
136 sess->use_ssl = !strcmp(scheme, "https");
137
138 /* set the hostname/port */
139 set_hostinfo(&sess->server, hostname, port);
140 set_hostport(&sess->server, sess->use_ssl?443:80);
141
142 #ifdef NEON_SSL
143 if (sess->use_ssl) {
144 sess->ssl_context = ne_ssl_context_create();
145 }
146 #endif
147
148 sess->scheme = ne_strdup(scheme);
149
150 /* Default expect-100 to OFF. */
151 sess->expect100_works = -1;
152 return sess;
153 }
154
ne_session_proxy(ne_session * sess,const char * hostname,unsigned int port)155 void ne_session_proxy(ne_session *sess, const char *hostname,
156 unsigned int port)
157 {
158 sess->use_proxy = 1;
159 if (sess->proxy.hostname) ne_free(sess->proxy.hostname);
160 set_hostinfo(&sess->proxy, hostname, port);
161 }
162
ne_set_error(ne_session * sess,const char * format,...)163 void ne_set_error(ne_session *sess, const char *format, ...)
164 {
165 va_list params;
166
167 va_start(params, format);
168 ne_vsnprintf(sess->error, sizeof sess->error, format, params);
169 va_end(params);
170 }
171
172
ne_set_progress(ne_session * sess,ne_progress progress,void * userdata)173 void ne_set_progress(ne_session *sess,
174 ne_progress progress, void *userdata)
175 {
176 sess->progress_cb = progress;
177 sess->progress_ud = userdata;
178 }
179
ne_set_status(ne_session * sess,ne_notify_status status,void * userdata)180 void ne_set_status(ne_session *sess,
181 ne_notify_status status, void *userdata)
182 {
183 sess->notify_cb = status;
184 sess->notify_ud = userdata;
185 }
186
ne_set_expect100(ne_session * sess,int use_expect100)187 void ne_set_expect100(ne_session *sess, int use_expect100)
188 {
189 if (use_expect100) {
190 sess->expect100_works = 1;
191 } else {
192 sess->expect100_works = -1;
193 }
194 }
195
ne_set_persist(ne_session * sess,int persist)196 void ne_set_persist(ne_session *sess, int persist)
197 {
198 sess->no_persist = !persist;
199 }
200
ne_set_read_timeout(ne_session * sess,int timeout)201 void ne_set_read_timeout(ne_session *sess, int timeout)
202 {
203 sess->rdtimeout = timeout;
204 }
205
206 #define UAHDR "User-Agent: "
207 #define AGENT " neon/" NEON_VERSION "\r\n"
208
ne_set_useragent(ne_session * sess,const char * token)209 void ne_set_useragent(ne_session *sess, const char *token)
210 {
211 if (sess->user_agent) ne_free(sess->user_agent);
212 sess->user_agent = ne_malloc(strlen(UAHDR) + strlen(AGENT) +
213 strlen(token) + 1);
214 #ifdef HAVE_STPCPY
215 strcpy(stpcpy(stpcpy(sess->user_agent, UAHDR), token), AGENT);
216 #else
217 strcat(strcat(strcpy(sess->user_agent, UAHDR), token), AGENT);
218 #endif
219 }
220
ne_get_server_hostport(ne_session * sess)221 const char *ne_get_server_hostport(ne_session *sess)
222 {
223 return sess->server.hostport;
224 }
225
ne_get_scheme(ne_session * sess)226 const char *ne_get_scheme(ne_session *sess)
227 {
228 return sess->scheme;
229 }
230
ne_fill_server_uri(ne_session * sess,ne_uri * uri)231 void ne_fill_server_uri(ne_session *sess, ne_uri *uri)
232 {
233 uri->host = ne_strdup(sess->server.hostname);
234 uri->port = sess->server.port;
235 uri->scheme = ne_strdup(sess->scheme);
236 }
237
ne_get_error(ne_session * sess)238 const char *ne_get_error(ne_session *sess)
239 {
240 return ne_strclean(sess->error);
241 }
242
ne_close_connection(ne_session * sess)243 void ne_close_connection(ne_session *sess)
244 {
245 if (sess->connected) {
246 NE_DEBUG(NE_DBG_SOCKET, "Closing connection.\n");
247 ne_sock_close(sess->socket);
248 sess->socket = NULL;
249 NE_DEBUG(NE_DBG_SOCKET, "Connection closed.\n");
250 } else {
251 NE_DEBUG(NE_DBG_SOCKET, "(Not closing closed connection!).\n");
252 }
253 sess->connected = 0;
254 }
255
ne_ssl_set_verify(ne_session * sess,ne_ssl_verify_fn fn,void * userdata)256 void ne_ssl_set_verify(ne_session *sess, ne_ssl_verify_fn fn, void *userdata)
257 {
258 sess->ssl_verify_fn = fn;
259 sess->ssl_verify_ud = userdata;
260 }
261
ne_ssl_provide_clicert(ne_session * sess,ne_ssl_provide_fn fn,void * userdata)262 void ne_ssl_provide_clicert(ne_session *sess,
263 ne_ssl_provide_fn fn, void *userdata)
264 {
265 sess->ssl_provide_fn = fn;
266 sess->ssl_provide_ud = userdata;
267 }
268
ne_ssl_trust_cert(ne_session * sess,const ne_ssl_certificate * cert)269 void ne_ssl_trust_cert(ne_session *sess, const ne_ssl_certificate *cert)
270 {
271 #ifdef NEON_SSL
272 ne_ssl_ctx_trustcert(sess->ssl_context, cert);
273 #endif
274 }
275
276
277
278