26#include <sys/socket.h>
27#include <netinet/in.h>
38#include "../cookies.h"
46#define MSG_BW(web, root, ...) \
48 if (a_Web_valid((web)) && (!(root) || (web)->flags & WEB_RootUrl)) \
49 a_UIcmd_set_msg((web)->bw, __VA_ARGS__); \
52#define _MSG_BW(web, root, ...)
71 Dstr *https_proxy_reply;
83 int running_the_queue;
120 char *env_proxy = getenv(
"http_proxy");
126 if (env_proxy && strlen(env_proxy))
160 dFree(http_proxyauth);
169 SocketData_t *S =
dNew0(SocketData_t, 1);
180 const FdMapEntry_t *e = v1;
182 return (fd != e->fd);
187 FdMapEntry_t *e =
dNew0(FdMapEntry_t, 1);
192 MSG_ERR(
"FD ENTRY ALREADY FOUND FOR %d\n", e->fd);
210 MSG(
"FD ENTRY NOT FOUND FOR %d\n", fd);
224 if (success && valid_web) {
229 MSG_BW(sd->web, 1,
"Could not establish connection.");
230 MSG(
"fd %d is done and failed\n", sd->SockFD);
237 MSG(
"**** but no luck with fme %p or sd\n", (
void *) fme);
244 sd->flags &= ~HTTP_SOCKET_QUEUED;
246 sd->connected_to = srv->host;
254 srv->running_the_queue++;
273 int SKey =
VOIDP2INT(sd->Info->LocalKey);
284 _MSG(
"Queue http%s://%s:%u len %d\n", srv->https ?
"s" :
"", srv->host,
287 if (--srv->running_the_queue == 0) {
288 if (srv->active_conns == 0)
304 S->flags &= ~HTTP_SOCKET_IOWATCH_ACTIVE;
317 if (S->connected_to) {
337 char *referer = NULL;
349 _MSG(
"http, referer='%s'\n", referer);
361 _MSG(
"submitting multipart/form-data!\n");
362 dstr =
dStr_new(
"multipart/form-data; boundary=\"");
365 const char *start =
URL_DATA(url)->str + 2;
366 char *eol = strchr(start,
'\r');
375 dstr =
dStr_new(
"application/x-www-form-urlencoded");
385 char *ptr, *cookies, *referer, *auth;
392 const char *accept_hdr_value =
395 "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
397 const char *connection_hdr_val =
400 if (use_proxy && !use_tls) {
404 if ((ptr = strrchr(request_uri->str,
'#')))
407 dStr_sprintf(proxy_auth,
"Proxy-Authorization: Basic %s\r\n",
424 "POST %s HTTP/1.1\r\n"
429 "Accept-Encoding: gzip, deflate\r\n"
435 "Content-Type: %s\r\n"
436 "Content-Length: %ld\r\n"
441 proxy_auth->str, referer, connection_hdr_val, content_type->
str,
448 "GET %s HTTP/1.1\r\n"
453 "Accept-Encoding: gzip, deflate\r\n"
464 proxy_auth->str, referer, connection_hdr_val,
466 "Pragma: no-cache\r\nCache-Control: no-cache\r\n" :
"",
493 MSG_BW(S->web, 1,
"Sending query%s...",
514 MSG_BW(S->web, 1,
"Tunnel secure connection through proxy...");
516 S->https_proxy_reply =
dStr_new(NULL);
522 MSG_BW(S->web, 1,
"Secure connection negotiation...");
536 int ret, connect_ret;
537 uint_t connect_ret_size =
sizeof(connect_ret);
540 S->flags &= ~HTTP_SOCKET_IOWATCH_ACTIVE;
542 ret = getsockopt(S->SockFD, SOL_SOCKET, SO_ERROR, &connect_ret,
545 if (ret < 0 || connect_ret != 0) {
547 MSG(
"Http_connect_socket_cb getsockopt ERROR: %s.\n",
550 MSG(
"Http_connect_socket_cb connect ERROR: %s.\n",
553 MSG(
"Http_connect_socket() will try another IP address.\n");
574 S->addr_list_idx++) {
576 struct sockaddr_in6 name;
578 struct sockaddr_in name;
580 socklen_t socket_len = 0;
582 if (S->addr_list_idx > 0 && S->SockFD >= 0) {
587 if ((S->SockFD = socket(dh->
af, SOCK_STREAM, IPPROTO_TCP)) < 0) {
588 MSG(
"Http_connect_socket socket() ERROR: %s\n",
dStrerror(errno));
594 fcntl(S->SockFD, F_SETFL, O_NONBLOCK | fcntl(S->SockFD, F_GETFL));
595 fcntl(S->SockFD, F_SETFD, FD_CLOEXEC | fcntl(S->SockFD, F_GETFD));
598 memset(&name, 0,
sizeof(name));
603 struct sockaddr_in *sin = (
struct sockaddr_in *)&name;
604 socket_len =
sizeof(
struct sockaddr_in);
605 sin->sin_family = dh->
af;
606 sin->sin_port = htons(S->connect_port);
607 memcpy(&sin->sin_addr, dh->
data, (
size_t)dh->
alen);
609 MSG(
"Connecting to %s:%u\n", inet_ntoa(sin->sin_addr),
617 struct sockaddr_in6 *sin6 = (
struct sockaddr_in6 *)&name;
618 socket_len =
sizeof(
struct sockaddr_in6);
619 sin6->sin6_family = dh->
af;
620 sin6->sin6_port = htons(S->connect_port);
621 memcpy(&sin6->sin6_addr, dh->
data, dh->
alen);
622 inet_ntop(dh->
af, dh->
data, buf,
sizeof(buf));
624 MSG(
"Connecting to [%s]:%u\n", buf, S->connect_port);
629 MSG_BW(S->web, 1,
"Contacting host...");
631 if (connect(S->SockFD, (
struct sockaddr *)&name, socket_len) == 0) {
641 if (errno == EINPROGRESS) {
647 MSG(
"Http_connect_socket connect ERROR: %s\n",
dStrerror(errno));
648 MSG(
"We will try another IP address.\n");
654 MSG(
"Http_connect_socket ran out of IP addrs to try.\n");
671 size_t host_len = strlen(hostname);
674 for (p = np; (tok =
dStrsep(&p,
" ")); ) {
675 int start = host_len - strlen(tok);
686 _MSG(
"Http_must_use_proxy: %s\n %s\n", hostname, ret ?
"YES":
"NO");
698 char *auth2, *proxy_auth, *retstr;
704 auth_len = strlen(auth1);
705 if (auth_len > 0 && !isdigit(auth1[auth_len - 1]))
716 "CONNECT %s HTTP/1.1\r\n"
748 if (Status == 0 && addr_list) {
751 S->addr_list = addr_list;
752 S->addr_list_idx = 0;
760 MSG_BW(S->web, 0,
"ERROR: DNS can't resolve %s", host);
806 MSG_BW(S->web, 1,
"DNS resolving %s", hostname);
848 old_sd->connect_port,
852 for (i = 0; i < n; i++) {
859 new_sd->SockFD = old_sd->SockFD;
861 old_sd->connected_to = NULL;
865 _MSG(
"Reusing fd %d for %s\n",new_sd->SockFD,
URL_STR(new_sd->url));
874 int old_fd = old_sd->SockFD;
884 void *Data1,
void *Data2)
918 MSG_WARN(
"Unused CCC 1B Op %d\n", Op);
933 MSG_WARN(
"Unused CCC 1F Op %d\n", Op);
937 }
else if (Branch == 2) {
944 if (sd->https_proxy_reply) {
947 if (strstr(sd->https_proxy_reply->str,
"\r\n\r\n")) {
948 if (sd->https_proxy_reply->len >= 12 &&
949 sd->https_proxy_reply->str[9] ==
'2') {
951 MSG(
"CONNECT through proxy succeeded. Reply:\n%s\n",
952 sd->https_proxy_reply->str);
954 sd->https_proxy_reply = NULL;
955 MSG_BW(sd->web, 1,
"Secure connection negotiation...");
958 MSG_BW(sd->web, 1,
"Can't connect through proxy to %s",
960 MSG(
"CONNECT through proxy failed. Server sent:\n%s\n",
961 sd->https_proxy_reply->str);
973 if (sd->https_proxy_reply) {
974 MSG(
"CONNECT through proxy failed. "
975 "Full reply not received:\n%s\n",
976 sd->https_proxy_reply->len ? sd->https_proxy_reply->str :
987 if (sd->https_proxy_reply) {
988 MSG(
"CONNECT through proxy failed. "
989 "Full reply not received:\n%s\n",
990 sd->https_proxy_reply->len ? sd->https_proxy_reply->str :
998 MSG_WARN(
"Unused CCC 2F Op %d\n", Op);
1009 if (!strcmp(Data2,
"FD")) {
1010 int fd = *(
int*)Data1;
1015 }
else if (!strcmp(Data2,
"reply_complete")) {
1028 MSG_WARN(
"Unused CCC 2B Op %d\n", Op);
1043 if ((sock->web->flags &
WEB_Image) == 0) {
1046 for (i = 0; i < n; i++) {
1066 if (port == srv->port && https == srv->https &&
1071 srv =
dNew0(Server_t, 1);
1073 srv->running_the_queue = 0;
1117 for (i = 0; i < n; i++) {
void a_IO_ccc(int Op, int Branch, int Dir, ChainLink *Info, void *Data1, void *Data2)
CCC function for the IO module.
char * a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri)
Return the authorization header for an HTTP query.
int a_Chain_bcb(int Op, ChainLink *Info, void *Data1, void *Data2)
Issue the backward callback of the 'Info' link.
DataBuf * a_Chain_dbuf_new(void *buf, int size, int code)
Allocate and initialize a new DataBuf structure.
ChainLink * a_Chain_link_new(ChainLink *AInfo, ChainFunction_t AFunc, int Direction, ChainFunction_t BFunc, int AtoB_branch, int BtoA_branch)
Create a new link from module A to module B.
int a_Chain_check(char *FuncStr, int Op, int Branch, int Dir, ChainLink *Info)
Check whether the CCC is operative.
int a_Chain_bfcb(int Op, ChainLink *Info, void *Data1, void *Data2)
Issue the backward callback of the 'Info' link and then the forward callback (used for OpAbort and Op...
int a_Chain_fcb(int Op, ChainLink *Info, void *Data1, void *Data2)
Issue the forward callback of the 'Info' link.
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
char * dStrsep(char **orig, const char *delim)
strsep() implementation
int dStrAsciiCasecmp(const char *s1, const char *s2)
void dStr_sprintfa(Dstr *ds, const char *format,...)
Printf-like function that appends.
void dStr_append(Dstr *ds, const char *s)
Append a C string to a Dstr.
void dList_insert_pos(Dlist *lp, void *data, int pos0)
Insert an element at a given position [0 based].
char * dStrdup(const char *s)
Dlist * dList_new(int size)
Create a new empty list.
int dList_length(Dlist *lp)
For completing the ADT.
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
void dList_remove_fast(Dlist *lp, const void *data)
Remove a data item without preserving order.
void dStr_free(Dstr *ds, int all)
Free a dillo string.
int dClose(int fd)
Close a FD handling EINTR.
void dStr_append_l(Dstr *ds, const char *s, int l)
Append a C string to a Dstr (providing length).
void dStr_append_c(Dstr *ds, int c)
Append one character.
void dStr_sprintf(Dstr *ds, const char *format,...)
Printf-like function.
Dstr * dStr_new(const char *s)
Create a new string.
void dList_append(Dlist *lp, void *data)
Append a data item to the list.
void dList_free(Dlist *lp)
Free a list (not its elements)
void * dList_find_custom(Dlist *lp, const void *data, dCompareFunc func)
Search a data item using a custom function.
const char * dStr_printable(Dstr *in, int maxlen)
Return a printable representation of the provided Dstr, limited to a length of roughly maxlen.
void dStr_truncate(Dstr *ds, int len)
Truncate a Dstr to be 'len' bytes long.
void dList_remove(Dlist *lp, const void *data)
#define dReturn_if_fail(expr)
#define dNew0(type, count)
#define dReturn_val_if_fail(expr, val)
void a_Dns_resolve(const char *hostname, DnsCallback_t cb_func, void *cb_data)
Return the IP for the given hostname using a callback.
void a_Http_set_proxy_passwd(const char *str)
Activate entered proxy password for HTTP.
static char * HTTP_Language_hdr
int a_Http_init(void)
Initialize proxy vars and Accept-Language header.
static int Http_get(ChainLink *Info, void *Data1)
Asynchronously create a new http connection for 'Url'.
static Dstr * Http_make_query_str(DilloWeb *web, bool_t use_proxy, bool_t use_tls)
Make the http query string.
static int Http_fd_map_cmp(const void *v1, const void *v2)
Compare by FD.
static Klist_t * ValidSocks
static void Http_fd_map_remove_all(void)
#define MSG_BW(web, root,...)
static bool_t Http_socket_reuse_compatible(SocketData_t *old, SocketData_t *new)
Can the old socket's fd be reused for the new socket?.
static const int HTTP_SOCKET_TO_BE_FREED
static void Http_server_remove(Server_t *srv)
static void Http_fd_map_add_entry(SocketData_t *sd)
static const int HTTP_SOCKET_QUEUED
static void Http_socket_reuse(int SKey)
If any entry in the socket data queue can reuse our connection, set it up and send off a new query.
static void Http_connect_socket(ChainLink *Info)
This function is called after the DNS succeeds in solving a hostname.
static void Http_send_query(SocketData_t *S)
Create and submit the HTTP query to the IO engine.
static int Http_must_use_proxy(const char *hostname)
Test proxy settings and check the no_proxy domains list.
static char * Http_get_referer(const DilloUrl *url)
Make the HTTP header's Referer line according to preferences (default is "host" i....
static void Http_socket_free(int SKey)
Free SocketData_t struct.
static DilloUrl * HTTP_Proxy
static void Http_socket_enqueue(Server_t *srv, SocketData_t *sock)
Add socket data to the queue.
void a_Http_connect_done(int fd, bool_t success)
static void Http_socket_activate(Server_t *srv, SocketData_t *sd)
static int Http_sock_new(void)
Create and init a new SocketData_t struct, insert into ValidSocks, and return a primary key for it.
static void Http_dns_cb(int Status, Dlist *addr_list, void *data)
Callback function for the DNS resolver.
static char * Http_get_connect_str(const DilloUrl *url)
Return a new string for the request used to tunnel HTTPS through a proxy.
static void Http_connect_tls(ChainLink *info)
Prepare an HTTPS connection.
static void Http_fd_map_remove_entry(int fd)
Remove and free entry from fd_map.
static char * HTTP_Proxy_Auth_base64
void a_Http_freeall(void)
Deallocate memory used by http module.
int a_Http_proxy_auth(void)
Tell whether the proxy auth is already set (user:password).
static Server_t * Http_server_get(const char *host, uint_t port, bool_t https)
static void Http_connect_socket_cb(int fd, void *data)
connect() couldn't complete before, but now it's ready, so let's try again.
static const int HTTP_SOCKET_USE_PROXY
static const int HTTP_SOCKET_TLS
static Dstr * Http_make_content_type(const DilloUrl *url)
Generate Content-Type header value for a POST query.
void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info, void *Data1, void *Data2)
CCC function for the HTTP module.
static void Http_connect_queued_sockets(Server_t *srv)
static void Http_servers_remove_all(void)
static const int HTTP_SOCKET_IOWATCH_ACTIVE
void a_IOwatch_add_fd(int fd, int when, Fl_FD_Handler Callback, void *usr_data=0)
Hook a Callback for a certain activities in a FD.
void a_IOwatch_remove_fd(int fd, int when)
Remove a Callback for a given FD (or just remove some events)
void a_Klist_remove(Klist_t *Klist, int Key)
Remove data by Key.
void * a_Klist_get_data(Klist_t *Klist, int Key)
Return the data pointer for a given Key (or NULL if not found)
void a_Klist_free(Klist_t **KlistPtr)
Free a Klist.
int a_Klist_insert(Klist_t **Klist, void *Data)
Insert a data pointer and return a key for it.
char * a_Misc_encode_base64(const char *in)
Encodes string using base64 encoding.
DilloPrefs prefs
Global Data.
char * a_Cookies_get_query(const DilloUrl *query_url, const DilloUrl *requester)
Return a string containing cookie data for an HTTP query.
Main data structure for CCC nodes.
A convenience data structure for passing data chunks between nodes.
char data[DILLO_ADDR_MAX]
bool_t http_persistent_conns
int flags
Additional info.
DilloUrl * url
Requested URL.
DilloUrl * requester
URL that caused this request, or < NULL if user-initiated.
void a_Tls_reset_server_state(const DilloUrl *url)
void a_Tls_connect(int fd, const DilloUrl *url)
int a_Tls_connect_ready(const DilloUrl *url)
The purpose here is to permit a single initial connection to a server.
void a_Tls_close_by_fd(int fd)
#define TLS_CONNECT_NEVER
#define TLS_CONNECT_READY
void a_Url_free(DilloUrl *url)
Free a DilloUrl.
DilloUrl * a_Url_new(const char *url_str, const char *base_url)
Transform (and resolve) an URL string into the respective DilloURL.
DilloUrl * a_Url_dup(const DilloUrl *ori)
Duplicate a Url structure.
int a_Web_valid(DilloWeb *web)
Validate a DilloWeb pointer.