4 #define _GNU_SOURCE /* XXX: we _WANT_ strcasestr() ! */
16 #include "config/options.h"
17 #include "main/event.h"
18 #include "network/connection.h"
19 #include "network/state.h"
20 #include "protocol/protocol.h"
21 #include "protocol/proxy.h"
22 #include "protocol/uri.h"
23 #include "util/memory.h"
24 #include "util/string.h"
28 proxy_probe_no_proxy(unsigned char *url
, unsigned char *no_proxy
)
30 unsigned char *slash
= strchr(url
, '/');
32 if (slash
) *slash
= '\0';
34 while (no_proxy
&& *no_proxy
) {
35 unsigned char *jumper
= strchr(no_proxy
, ',');
38 if (jumper
) *jumper
= '\0';
40 if (c_strcasestr(url
, no_proxy
)) {
41 if (jumper
) *jumper
= ',';
42 if (slash
) *slash
= '/';
52 if (slash
) *slash
= '/';
57 proxy_uri(struct uri
*uri
, unsigned char *proxy
,
58 struct connection_state
*error_state
)
62 if (init_string(&string
)
63 && string_concat(&string
, "proxy://", proxy
, "/",
64 (unsigned char *) NULL
)
65 && add_uri_to_string(&string
, uri
, URI_BASE
)) {
66 /* There is no need to use URI_BASE when calling get_uri()
67 * because URI_BASE should not add any fragments in the first
69 uri
= get_uri(string
.source
, 0);
70 /* XXX: Assume the problem is due to @proxy having bad format.
71 * This is a lot faster easier than checking the format. */
73 *error_state
= connection_state(S_PROXY_ERROR
);
76 *error_state
= connection_state(S_OUT_OF_MEM
);
83 static unsigned char *
84 strip_proxy_protocol(unsigned char *proxy
,
85 unsigned char *strip1
, unsigned char *strip2
)
87 assert(proxy
&& *proxy
);
89 if (!c_strncasecmp(proxy
, strip1
, strlen(strip1
)))
90 proxy
+= strlen(strip1
);
91 else if (strip2
&& !c_strncasecmp(proxy
, strip2
, strlen(strip2
)))
92 proxy
+= strlen(strip2
);
97 /* TODO: We could of course significantly simplify the calling convention by
98 * autogenerating most of the parameters from protocol name. Having a function
99 * exported by protocol/protocol.* dedicated to that would be nice too.
101 static unsigned char *
102 get_protocol_proxy(unsigned char *opt
,
103 unsigned char *env1
, unsigned char *env2
,
104 unsigned char *strip1
, unsigned char *strip2
)
106 unsigned char *proxy
;
108 proxy
= get_opt_str(opt
, NULL
);
109 if (!*proxy
) proxy
= getenv(env1
);
110 if (!proxy
|| !*proxy
) proxy
= getenv(env2
);
112 if (proxy
&& *proxy
) {
113 proxy
= strip_proxy_protocol(proxy
, strip1
, strip2
);
120 get_proxy_worker(struct uri
*uri
, unsigned char *proxy
,
121 struct connection_state
*error_state
)
123 unsigned char *protocol_proxy
= NULL
;
127 proxy
= strip_proxy_protocol(proxy
, "http://", "ftp://");
129 return proxy_uri(uri
, proxy
, error_state
);
132 /* "" from script_hook_get_proxy() */
133 return get_composed_uri(uri
, URI_BASE
);
136 switch (uri
->protocol
) {
138 protocol_proxy
= get_protocol_proxy("protocol.http.proxy.host",
139 "HTTP_PROXY", "http_proxy",
144 /* As Timo Lindfors explains, the communication between ELinks
145 * and the proxy server is never encrypted, altho the proxy
146 * might be used to transfer encrypted data between Web client
147 * and Web server. (Some proxy servers might allow encrypted
148 * communication between the Web client and the proxy
149 * but ELinks does not support that.) */
150 /* So, don't check whether the URI for the proxy begins
151 * with "https://" but rather check for "http://".
152 * Maybe we should allow either -- ELinks uses HTTP
153 * to communicate with the proxy when we use it for FTP, but we
154 * check for "ftp://" below; and what about 'be liberal in what
155 * you accept' (altho that is usually applied to data received
156 * from remote systems, not to user input)? -- Miciah */
157 protocol_proxy
= get_protocol_proxy("protocol.https.proxy.host",
158 "HTTPS_PROXY", "https_proxy",
163 protocol_proxy
= get_protocol_proxy("protocol.ftp.proxy.host",
164 "FTP_PROXY", "ftp_proxy",
165 "ftp://", "http://");
169 if (protocol_proxy
&& *protocol_proxy
) {
170 unsigned char *no_proxy
;
171 unsigned char *slash
= strchr(protocol_proxy
, '/');
173 if (slash
) *slash
= 0;
175 no_proxy
= get_opt_str("protocol.no_proxy", NULL
);
176 if (!*no_proxy
) no_proxy
= getenv("NO_PROXY");
177 if (!no_proxy
|| !*no_proxy
) no_proxy
= getenv("no_proxy");
179 if (!proxy_probe_no_proxy(uri
->host
, no_proxy
))
180 return proxy_uri(uri
, protocol_proxy
, error_state
);
183 return get_composed_uri(uri
, URI_BASE
);
187 get_proxy_uri(struct uri
*uri
, struct connection_state
*error_state
)
189 if (uri
->protocol
== PROTOCOL_PROXY
) {
190 return get_composed_uri(uri
, URI_BASE
);
192 #ifdef CONFIG_SCRIPTING
193 unsigned char *tmp
= NULL
;
194 static int get_proxy_event_id
= EVENT_NONE
;
196 set_event_id(get_proxy_event_id
, "get-proxy");
197 trigger_event(get_proxy_event_id
, &tmp
, struri(uri
));
199 uri
= get_proxy_worker(uri
, tmp
, error_state
);
203 return get_proxy_worker(uri
, NULL
, error_state
);
209 get_proxied_uri(struct uri
*uri
)
211 if (uri
->protocol
== PROTOCOL_PROXY
)
212 return get_uri(uri
->data
, URI_BASE
);
214 return get_composed_uri(uri
, URI_BASE
);