YAZ 5.38.1
url.c
Go to the documentation of this file.
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
9#if HAVE_CONFIG_H
10#include <config.h>
11#endif
12
13#include <yaz/url.h>
14#include <yaz/comstack.h>
15#include <yaz/log.h>
16#include <yaz/wrbuf.h>
17#include <yaz/cookie.h>
18#include <yaz/poll.h>
19
33
35{
36 yaz_url_t p = xmalloc(sizeof(*p));
39 p->proxy = 0;
40 p->max_redirects = 10;
41 p->w_error = wrbuf_alloc();
42 p->verbose = 0;
43 p->timeout_sec = 30;
44 p->timeout_ns = 0;
46 p->check_cert = 0;
47 p->cert_fname = 0;
48 return p;
49}
50
52{
53 if (p)
54 {
57 xfree(p->proxy);
60 xfree(p->cert_fname);
61 xfree(p);
62 }
63}
64
65void yaz_url_set_proxy(yaz_url_t p, const char *proxy)
66{
67 xfree(p->proxy);
68 p->proxy = 0;
69 if (proxy && *proxy)
70 p->proxy = xstrdup(proxy);
71}
72
74{
75 p->max_redirects = num;
76}
77
79{
80 p->verbose = num;
81}
82
83void yaz_url_set_timeout(yaz_url_t p, int sec, int ns)
84{
85 p->timeout_sec = sec;
86 p->timeout_ns = ns;
87}
88
89void yaz_url_set_check_cert(yaz_url_t p, int check_cert)
90{
91 p->check_cert = check_cert;
92}
93
94void yaz_url_set_cert_fname(yaz_url_t p, const char *fname)
95{
96 xfree(p->cert_fname);
97 p->cert_fname = 0;
98 if (fname && *fname)
99 p->cert_fname = xstrdup(fname);
100}
101
102static void extract_user_pass(NMEM nmem,
103 const char *uri,
104 char **uri_lean, char **http_user,
105 char **http_pass)
106{
107 const char *cp1 = strchr(uri, '/');
108 *uri_lean = 0;
109 *http_user = 0;
110 *http_pass = 0;
111 if (cp1 && cp1 > uri)
112 {
113 cp1--;
114
115 if (!strncmp(cp1, "://", 3))
116 {
117 const char *cp3 = 0;
118 const char *cp2 = cp1 + 3;
119 while (*cp2 && *cp2 != '/' && *cp2 != '@')
120 {
121 if (*cp2 == ':')
122 cp3 = cp2;
123 cp2++;
124 }
125 if (*cp2 == '@' && cp3)
126 {
127 *uri_lean = nmem_malloc(nmem, strlen(uri) + 1);
128 memcpy(*uri_lean, uri, cp1 + 3 - uri);
129 strcpy(*uri_lean + (cp1 + 3 - uri), cp2 + 1);
130
131 *http_user = nmem_strdupn(nmem, cp1 + 3, cp3 - (cp1 + 3));
132 *http_pass = nmem_strdupn(nmem, cp3 + 1, cp2 - (cp3 + 1));
133 }
134 }
135 }
136 if (*uri_lean == 0)
137 *uri_lean = nmem_strdup(nmem, uri);
138}
139
141{
142 return wrbuf_cstr(p->w_error);
143}
144
145static void log_warn(yaz_url_t p)
146{
147 yaz_log(YLOG_WARN, "yaz_url: %s", wrbuf_cstr(p->w_error));
148}
149
151{
152 const char *details;
153 int code = cs_get_error(conn, &details);
154 wrbuf_printf(p->w_error, ": cs=%d msg=%s", code, cs_errmsg(code));
155 if (details)
156 wrbuf_printf(p->w_error, " details=%s", details);
157}
158
160 const char *method,
161 Z_HTTP_Header *user_headers,
162 const char *buf, size_t len)
163{
164 Z_HTTP_Response *res;
165 int number_of_redirects = 0;
166
167 odr_reset(p->odr_out);
170 while (1)
171 {
172 void *add;
173 COMSTACK conn = 0;
174 int code;
175 const char *location = 0;
176 char *http_user = 0;
177 char *http_pass = 0;
178 char *uri_lean = 0;
179 int proxy_mode = 0;
180 int ret;
181 Z_GDU *gdu;
182 int cs_flags = p->check_cert ? CS_FLAGS_CHECK_CERT : 0;
183
184 res = 0;
185 extract_user_pass(p->odr_out->mem, uri, &uri_lean,
186 &http_user, &http_pass);
187 conn = cs_create_host2(uri_lean, cs_flags, &add, p->proxy, &proxy_mode);
188 if (!conn)
189 {
190 wrbuf_printf(p->w_error, "Can not resolve URL %s", uri);
191 log_warn(p);
192 return res;
193 }
194 if (p->cert_fname)
196 gdu = z_get_HTTP_Request_uri(p->odr_out, uri_lean, 0, proxy_mode);
197 gdu->u.HTTP_Request->method = odr_strdup(p->odr_out, method);
198 yaz_cookies_request(p->cookies, p->odr_out, gdu->u.HTTP_Request);
199 for ( ; user_headers; user_headers = user_headers->next)
200 {
201 /* prefer new Host over user-supplied Host */
202 if (!strcmp(user_headers->name, "Host"))
203 ;
204 /* prefer user-supplied User-Agent over YAZ' own */
205 else if (!strcmp(user_headers->name, "User-Agent"))
206 z_HTTP_header_set(p->odr_out, &gdu->u.HTTP_Request->headers,
207 user_headers->name, user_headers->value);
208 else
209 z_HTTP_header_add(p->odr_out, &gdu->u.HTTP_Request->headers,
210 user_headers->name, user_headers->value);
211 }
212 if (http_user && http_pass)
214 &gdu->u.HTTP_Request->headers,
215 http_user, http_pass);
216 if (buf && len)
217 {
218 gdu->u.HTTP_Request->content_buf = (char *) buf;
219 gdu->u.HTTP_Request->content_len = len;
220 }
221 if (!z_GDU(p->odr_out, &gdu, 0, 0))
222 {
223 wrbuf_printf(p->w_error, "Can not encode HTTP request for URL %s",
224 uri);
225 log_warn(p);
226 }
227 else if ((ret = cs_connect(conn, add)) < 0)
228 {
229 wrbuf_printf(p->w_error, "Can not connect to URL %s", uri);
230 add_comstack_details(p, conn);
231 log_warn(p);
232 }
233 else
234 {
235 char *netbuffer = 0;
236 int netlen = 0;
237 int len_out;
238 char *buf_out = odr_getbuf(p->odr_out, &len_out, 0);
239 int state = 0; /* 0=connect phase, 1=send, 2=recv */
240 if (p->verbose)
241 fwrite(buf_out, 1, len_out, stdout);
242 if (!strcmp(gdu->u.HTTP_Request->method, "HEAD"))
243 cs_set_head_only(conn, 1);
244 if (ret == 0)
245 state = 1; /* connect complete, so send phase */
246 while (1)
247 {
248 if (ret == 1) /* incomplete , wait */
249 {
250 struct yaz_poll_fd yp;
253 if (conn->io_pending & CS_WANT_WRITE)
255 if (conn->io_pending & CS_WANT_READ)
257 yp.fd = cs_fileno(conn);
259 ret = yaz_poll(&yp, 1, p->timeout_sec, p->timeout_ns);
260 if (ret == 0)
261 {
262 wrbuf_printf(p->w_error, "timeout URL %s", uri);
263 break;
264 }
265 else if (ret < 0)
266 {
267 wrbuf_printf(p->w_error, "poll error URL %s", uri);
268 break;
269 }
270 }
271 if (state == 0) /* connect phase */
272 {
273 ret = cs_rcvconnect(conn);
274 if (ret < 0)
275 {
276 wrbuf_printf(p->w_error, "cs_rcvconnect failed for URL %s", uri);
277 add_comstack_details(p, conn);
278 log_warn(p);
279 break;
280 }
281 else if (ret == 0)
282 state = 1;
283 }
284 else if (state == 1) /* write request phase */
285 {
286 ret = cs_put(conn, buf_out, len_out);
287 if (ret < 0)
288 {
289 wrbuf_printf(p->w_error, "cs_put fail for URL %s", uri);
290 add_comstack_details(p, conn);
291 log_warn(p);
292 break;
293 }
294 else if (ret == 0)
295 {
296 state = 2;
297 }
298 }
299 else if (state == 2) /* read response phase */
300 {
301 ret = cs_get(conn, &netbuffer, &netlen);
302 if (ret <= 0)
303 {
304 if (ret < 0)
305 {
307 "cs_get failed for URL %s", uri);
308 add_comstack_details(p, conn);
309 }
310 else
312 "Connection closed while reading"
313 " URL %s", uri);
314 log_warn(p);
315 break;
316 }
317 else if (ret > 1)
318 {
319 Z_GDU *gdu;
320 if (p->verbose)
321 fwrite(netbuffer, 1, ret, stdout);
322 odr_setbuf(p->odr_in, netbuffer, ret, 0);
323 if (!z_GDU(p->odr_in, &gdu, 0, 0)
324 || gdu->which != Z_GDU_HTTP_Response)
325 {
326 wrbuf_printf(p->w_error, "HTTP decoding fail for "
327 "URL %s", uri);
328 log_warn(p);
329 }
330 else
331 {
332 res = gdu->u.HTTP_Response;
333 break;
334 }
335 }
336 }
337 }
338 xfree(netbuffer);
339 }
340 cs_close(conn);
341 if (!res)
342 break;
343 code = res->code;
344 location = z_HTTP_header_lookup(res->headers, "Location");
345 if (++number_of_redirects <= p->max_redirects &&
346 location && (code == 301 || code == 302 || code == 307))
347 {
348 int host_change = 0;
349 const char *nlocation = yaz_check_location(p->odr_in, uri,
350 location, &host_change);
351
352 odr_reset(p->odr_out);
353 uri = odr_strdup(p->odr_out, nlocation);
354 }
355 else
356 break;
358 odr_reset(p->odr_in);
359 }
360 return res;
361}
362
363/*
364 * Local variables:
365 * c-basic-offset: 4
366 * c-file-style: "Stroustrup"
367 * indent-tabs-mode: nil
368 * End:
369 * vim: shiftwidth=4 tabstop=8 expandtab
370 */
int cs_get_error(COMSTACK cs, const char **details)
Returns the last COMSTACK error and optional transport details.
Definition comstack.c:51
COMSTACK cs_create_host2(const char *vhost, int flags, void **vp, const char *proxy_host, int *proxy_mode)
Creates an endpoint and selects direct or proxy connection handling.
Definition comstack.c:189
const char * cs_errmsg(int n)
Returns a static message for a COMSTACK error code.
Definition comstack.c:39
int cs_set_head_only(COMSTACK cs, int head_only)
Selects HTTP header-only framing for TCP/IP, SSL or UNIX transports.
Definition comstack.c:524
Transport-independent communication endpoints for BER and HTTP.
#define cs_close(handle)
Closes the socket and frees the endpoint and its transport state.
Definition comstack.h:223
#define cs_connect(handle, address)
Starts an outgoing connection.
Definition comstack.h:171
#define cs_put(handle, buf, size)
Sends a complete message.
Definition comstack.h:143
#define CS_WANT_READ
Definition comstack.h:302
#define cs_get(handle, buf, size)
Receives a BER or HTTP message.
Definition comstack.h:155
#define CS_FLAGS_CHECK_CERT
Definition comstack.h:566
#define cs_fileno(handle)
Returns the socket descriptor, or -1 if none has been created.
Definition comstack.h:247
struct comstack * COMSTACK
Communication endpoint; release with cs_close.
Definition comstack.h:48
#define CS_WANT_WRITE
Definition comstack.h:304
#define cs_rcvconnect(handle)
Continues a pending outgoing connection, including TLS or CONNECT.
Definition comstack.h:176
void yaz_cookies_reset(yaz_cookies_t yc)
Definition cookie.c:41
void yaz_cookies_destroy(yaz_cookies_t yc)
Definition cookie.c:35
yaz_cookies_t yaz_cookies_create(void)
Definition cookie.c:28
void yaz_cookies_request(yaz_cookies_t yc, ODR odr, Z_HTTP_Request *req)
Definition cookie.c:98
void yaz_cookies_response(yaz_cookies_t yc, Z_HTTP_Response *res)
Definition cookie.c:60
HTTP cookie handling.
struct yaz_cookies_s * yaz_cookies_t
Definition cookie.h:40
void z_HTTP_header_add_basic_auth(ODR o, Z_HTTP_Header **hp, const char *username, const char *password)
Definition http.c:135
void z_HTTP_header_set(ODR o, Z_HTTP_Header **hp, const char *n, const char *v)
Definition http.c:163
const char * yaz_check_location(ODR odr, const char *uri, const char *location, int *host_change)
Definition http.c:664
const char * z_HTTP_header_lookup(const Z_HTTP_Header *hp, const char *n)
Definition http.c:196
Z_GDU * z_get_HTTP_Request_uri(ODR odr, const char *uri, const char *args, int use_full_uri)
Definition http.c:254
void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n, const char *v)
Definition http.c:152
void yaz_log(int level, const char *fmt,...)
Writes log message.
Definition log.c:487
Logging utility.
#define YLOG_WARN
log level: warning
Definition log.h:46
void * nmem_malloc(NMEM n, size_t size)
allocates memory block on NMEM handle
Definition nmem.c:145
struct nmem_control * NMEM
NMEM handle (an opaque pointer to memory).
Definition nmem.h:44
char * nmem_strdup(NMEM mem, const char *src)
allocates string on NMEM handle (similar strdup)
Definition nmemsdup.c:19
char * nmem_strdupn(NMEM mem, const char *src, size_t n)
allocates string of certain size on NMEM handle
Definition nmemsdup.c:34
char * odr_getbuf(ODR o, int *len, int *size)
Definition odr.c:276
ODR odr_createmem(int direction)
Definition odr.c:198
void odr_setbuf(ODR o, char *buf, int len, int can_grow)
Definition odr.c:266
void odr_destroy(ODR o)
Definition odr.c:252
void odr_reset(ODR o)
Definition odr.c:224
#define ODR_DECODE
Definition odr.h:95
struct odr * ODR
Definition odr.h:121
#define ODR_ENCODE
Definition odr.h:96
char * odr_strdup(ODR o, const char *str)
Definition odr_mem.c:36
int yaz_poll(struct yaz_poll_fd *fds, int num_fds, int sec, int nsec)
poll wrapper for poll or select
Definition poll.c:161
Poll, select wrappers.
#define yaz_poll_add(var, value)
Definition poll.h:76
yaz_poll_mask
select/poll masks .. timeout is "output" only
Definition poll.h:41
@ yaz_poll_read
Definition poll.h:43
@ yaz_poll_except
Definition poll.h:45
@ yaz_poll_none
Definition poll.h:42
@ yaz_poll_write
Definition poll.h:44
Definition zgdu.h:68
int which
Definition zgdu.h:69
union Z_GDU::@057307356220171136236350364324260103365227025100 u
char * name
Definition zgdu.h:43
Z_HTTP_Header * next
Definition zgdu.h:45
char * value
Definition zgdu.h:44
Z_HTTP_Header * headers
Definition zgdu.h:60
unsigned io_pending
Definition comstack.h:88
NMEM mem
Definition odr.h:130
select/poll fd info
Definition poll.h:50
enum yaz_poll_mask input_mask
Definition poll.h:52
int fd
Definition poll.h:56
Definition url.c:20
int verbose
Definition url.c:26
yaz_cookies_t cookies
Definition url.c:29
int timeout_ns
Definition url.c:28
int check_cert
Definition url.c:30
char * cert_fname
Definition url.c:31
int max_redirects
Definition url.c:24
ODR odr_out
Definition url.c:22
int timeout_sec
Definition url.c:27
WRBUF w_error
Definition url.c:25
char * proxy
Definition url.c:23
ODR odr_in
Definition url.c:21
int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
Selects certificate and private key files for a TLS endpoint.
Definition tcpip.c:1698
void yaz_url_set_timeout(yaz_url_t p, int sec, int ns)
sets I/O timeout
Definition url.c:83
yaz_url_t yaz_url_create(void)
creates a URL fetcher handle
Definition url.c:34
void yaz_url_set_cert_fname(yaz_url_t p, const char *fname)
sets file with client-side certificate
Definition url.c:94
static void extract_user_pass(NMEM nmem, const char *uri, char **uri_lean, char **http_user, char **http_pass)
Definition url.c:102
Z_HTTP_Response * yaz_url_exec(yaz_url_t p, const char *uri, const char *method, Z_HTTP_Header *user_headers, const char *buf, size_t len)
executes the actual HTTP request (including redirects, etc)
Definition url.c:159
static void log_warn(yaz_url_t p)
Definition url.c:145
void yaz_url_set_max_redirects(yaz_url_t p, int num)
sets maximum number of redirects
Definition url.c:73
void yaz_url_destroy(yaz_url_t p)
destroys a URL fetcher
Definition url.c:51
void yaz_url_set_proxy(yaz_url_t p, const char *proxy)
sets proxy for URL fetcher
Definition url.c:65
const char * yaz_url_get_error(yaz_url_t p)
get last error from yaz_url_exec
Definition url.c:140
static void add_comstack_details(yaz_url_t p, COMSTACK conn)
Definition url.c:150
void yaz_url_set_check_cert(yaz_url_t p, int check_cert)
sets whether to check SSL certificates
Definition url.c:89
void yaz_url_set_verbose(yaz_url_t p, int num)
sets verbose level 0=none, >0 verbose
Definition url.c:78
URL fetch utility.
struct yaz_url * yaz_url_t
handle for our URL fetcher
Definition url.h:41
void wrbuf_destroy(WRBUF b)
destroy WRBUF and its buffer
Definition wrbuf.c:38
const char * wrbuf_cstr(WRBUF b)
returns WRBUF content as C-string
Definition wrbuf.c:299
void wrbuf_rewind(WRBUF b)
empty WRBUF content (length of buffer set to 0)
Definition wrbuf.c:47
WRBUF wrbuf_alloc(void)
construct WRBUF
Definition wrbuf.c:25
void wrbuf_printf(WRBUF b, const char *fmt,...)
writes printf result to WRBUF
Definition wrbuf.c:189
Header for WRBUF (growing buffer).
struct wrbuf * WRBUF
#define xstrdup(s)
utility macro which calls xstrdup_f
Definition xmalloc.h:55
#define xfree(x)
utility macro which calls xfree_f
Definition xmalloc.h:53
#define xmalloc(x)
utility macro which calls malloc_f
Definition xmalloc.h:49
#define Z_GDU_HTTP_Response
Definition zgdu.h:67
int z_GDU(ODR o, Z_GDU **p, int opt, const char *name)
Definition zgdu.c:17