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