2005-09-15 09:58:31 -04:00
|
|
|
/* Proxy handling */
|
|
|
|
|
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE /* XXX: we _WANT_ strcasestr() ! */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "config/options.h"
|
|
|
|
#include "main/event.h"
|
|
|
|
#include "network/connection.h"
|
2006-01-28 15:21:09 -05:00
|
|
|
#include "network/state.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "protocol/protocol.h"
|
|
|
|
#include "protocol/proxy.h"
|
|
|
|
#include "protocol/uri.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
#include "util/string.h"
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
proxy_probe_no_proxy(unsigned char *url, unsigned char *no_proxy)
|
|
|
|
{
|
|
|
|
unsigned char *slash = strchr(url, '/');
|
|
|
|
|
|
|
|
if (slash) *slash = '\0';
|
|
|
|
|
|
|
|
while (no_proxy && *no_proxy) {
|
|
|
|
unsigned char *jumper = strchr(no_proxy, ',');
|
|
|
|
|
|
|
|
skip_space(no_proxy);
|
|
|
|
if (jumper) *jumper = '\0';
|
|
|
|
|
|
|
|
if (strcasestr(url, no_proxy)) {
|
|
|
|
if (jumper) *jumper = ',';
|
|
|
|
if (slash) *slash = '/';
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
no_proxy = jumper;
|
|
|
|
if (jumper) {
|
|
|
|
*jumper = ',';
|
|
|
|
no_proxy++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slash) *slash = '/';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct uri *
|
2006-01-28 15:21:09 -05:00
|
|
|
proxy_uri(struct uri *uri, unsigned char *proxy,
|
|
|
|
enum connection_state *connection_state)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
struct string string;
|
|
|
|
|
|
|
|
if (init_string(&string)
|
2007-03-11 07:01:50 -04:00
|
|
|
&& string_concat(&string, "proxy://", proxy, "/",
|
|
|
|
(unsigned char *) NULL)
|
2005-09-15 09:58:31 -04:00
|
|
|
&& add_uri_to_string(&string, uri, URI_BASE)) {
|
|
|
|
/* There is no need to use URI_BASE when calling get_uri()
|
|
|
|
* because URI_BASE should not add any fragments in the first
|
|
|
|
* place. */
|
|
|
|
uri = get_uri(string.source, 0);
|
|
|
|
/* XXX: Assume the problem is due to @proxy having bad format.
|
|
|
|
* This is a lot faster easier than checking the format. */
|
|
|
|
if (!uri)
|
|
|
|
*connection_state = S_PROXY_ERROR;
|
|
|
|
} else {
|
|
|
|
uri = NULL;
|
|
|
|
*connection_state = S_OUT_OF_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
done_string(&string);
|
|
|
|
return uri;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char *
|
|
|
|
strip_proxy_protocol(unsigned char *proxy,
|
|
|
|
unsigned char *strip1, unsigned char *strip2)
|
|
|
|
{
|
|
|
|
assert(proxy && *proxy);
|
|
|
|
|
|
|
|
if (!strncasecmp(proxy, strip1, strlen(strip1)))
|
|
|
|
proxy += strlen(strip1);
|
|
|
|
else if (strip2 && !strncasecmp(proxy, strip2, strlen(strip2)))
|
|
|
|
proxy += strlen(strip2);
|
|
|
|
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: We could of course significantly simplify the calling convention by
|
|
|
|
* autogenerating most of the parameters from protocol name. Having a function
|
|
|
|
* exported by protocol/protocol.* dedicated to that would be nice too.
|
|
|
|
* --pasky */
|
|
|
|
static unsigned char *
|
|
|
|
get_protocol_proxy(unsigned char *opt,
|
|
|
|
unsigned char *env1, unsigned char *env2,
|
|
|
|
unsigned char *strip1, unsigned char *strip2)
|
|
|
|
{
|
|
|
|
unsigned char *proxy;
|
|
|
|
|
|
|
|
proxy = get_opt_str(opt);
|
|
|
|
if (!*proxy) proxy = getenv(env1);
|
|
|
|
if (!proxy || !*proxy) proxy = getenv(env2);
|
|
|
|
|
|
|
|
if (proxy && *proxy) {
|
|
|
|
proxy = strip_proxy_protocol(proxy, strip1, strip2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct uri *
|
2006-01-28 15:21:09 -05:00
|
|
|
get_proxy_worker(struct uri *uri, unsigned char *proxy,
|
|
|
|
enum connection_state *connection_state)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
unsigned char *protocol_proxy = NULL;
|
|
|
|
|
|
|
|
if (proxy) {
|
|
|
|
if (*proxy) {
|
|
|
|
proxy = strip_proxy_protocol(proxy, "http://", "ftp://");
|
|
|
|
|
|
|
|
return proxy_uri(uri, proxy, connection_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* "" from script_hook_get_proxy() */
|
|
|
|
return get_composed_uri(uri, URI_BASE);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (uri->protocol) {
|
|
|
|
case PROTOCOL_HTTP:
|
|
|
|
protocol_proxy = get_protocol_proxy("protocol.http.proxy.host",
|
|
|
|
"HTTP_PROXY", "http_proxy",
|
|
|
|
"http://", NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROTOCOL_HTTPS:
|
|
|
|
/* As Timo Lindfors explains, the communication between ELinks
|
|
|
|
* and the proxy server is never encrypted, altho the proxy
|
|
|
|
* might be used to transfer encrypted data between Web client
|
|
|
|
* and Web server. (Some proxy servers might allow encrypted
|
|
|
|
* communication between the Web client and the proxy
|
|
|
|
* but ELinks does not support that.) */
|
|
|
|
/* So, don't check whether the URI for the proxy begins
|
|
|
|
* with "https://" but rather check for "http://".
|
|
|
|
* Maybe we should allow either -- ELinks uses HTTP
|
|
|
|
* to communicate with the proxy when we use it for FTP, but we
|
|
|
|
* check for "ftp://" below; and what about 'be liberal in what
|
|
|
|
* you accept' (altho that is usually applied to data received
|
|
|
|
* from remote systems, not to user input)? -- Miciah */
|
|
|
|
protocol_proxy = get_protocol_proxy("protocol.https.proxy.host",
|
|
|
|
"HTTPS_PROXY", "https_proxy",
|
|
|
|
"http://", NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROTOCOL_FTP:
|
|
|
|
protocol_proxy = get_protocol_proxy("protocol.ftp.proxy.host",
|
|
|
|
"FTP_PROXY", "ftp_proxy",
|
|
|
|
"ftp://", "http://");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (protocol_proxy && *protocol_proxy) {
|
|
|
|
unsigned char *no_proxy;
|
|
|
|
unsigned char *slash = strchr(protocol_proxy, '/');
|
|
|
|
|
|
|
|
if (slash) *slash = 0;
|
|
|
|
|
|
|
|
no_proxy = get_opt_str("protocol.no_proxy");
|
|
|
|
if (!*no_proxy) no_proxy = getenv("NO_PROXY");
|
|
|
|
if (!no_proxy || !*no_proxy) no_proxy = getenv("no_proxy");
|
|
|
|
|
|
|
|
if (!proxy_probe_no_proxy(uri->host, no_proxy))
|
|
|
|
return proxy_uri(uri, protocol_proxy, connection_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
return get_composed_uri(uri, URI_BASE);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct uri *
|
2006-01-28 15:21:09 -05:00
|
|
|
get_proxy_uri(struct uri *uri, enum connection_state *connection_state)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
if (uri->protocol == PROTOCOL_PROXY) {
|
|
|
|
return get_composed_uri(uri, URI_BASE);
|
|
|
|
} else {
|
|
|
|
#ifdef CONFIG_SCRIPTING
|
|
|
|
unsigned char *tmp = NULL;
|
|
|
|
static int get_proxy_event_id = EVENT_NONE;
|
|
|
|
|
|
|
|
set_event_id(get_proxy_event_id, "get-proxy");
|
|
|
|
trigger_event(get_proxy_event_id, &tmp, struri(uri));
|
|
|
|
|
|
|
|
uri = get_proxy_worker(uri, tmp, connection_state);
|
|
|
|
mem_free_if(tmp);
|
|
|
|
return uri;
|
|
|
|
#else
|
|
|
|
return get_proxy_worker(uri, NULL, connection_state);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct uri *
|
|
|
|
get_proxied_uri(struct uri *uri)
|
|
|
|
{
|
|
|
|
if (uri->protocol == PROTOCOL_PROXY)
|
|
|
|
return get_uri(uri->data, URI_BASE);
|
|
|
|
|
|
|
|
return get_composed_uri(uri, URI_BASE);
|
|
|
|
}
|