📄 http.c
字号:
/* * File: http.c * * Copyright (C) 2000, 2001 Jorge Arellano Cid <jcid@dillo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * HTTP connect functions */#include <config.h>#include <unistd.h>#include <errno.h> /* for errno */#include <string.h> /* for strstr */#include <stdlib.h>#include <signal.h>#include <fcntl.h>#include <sys/wait.h>#include <sys/socket.h> /* for lots of socket stuff */#include <netinet/in.h> /* for ntohl and stuff */#include <arpa/inet.h> /* for inet_ntop */#include "Url.h"#include "IO.h"#include "../klist.h"#include "../dns.h"#include "../cache.h"#include "../web.h"#include "../interface.h"#include "../cookies.h"#include "../prefs.h"#include "../misc.h"/* Used to send a message to the bw's status bar */#define BW_MSG(web, root, fmt...) \G_STMT_START { \ if (a_Web_valid((web)) && (!(root) || (web)->flags & WEB_RootUrl)) \ a_Interface_msg((web)->bw, fmt); \} G_STMT_END#define DEBUG_LEVEL 5#include "../debug.h"/* 'Url' and 'web' are just references (no need to deallocate them here). */typedef struct { gint SockFD; const DilloUrl *Url; /* reference to original URL */ guint port; /* need a separate port in order to support PROXY */ gboolean use_proxy; /* indicates whether to use proxy or not */ DilloWeb *web; /* reference to client's web structure */ GSList *addr_list; /* Holds the DNS answer */ GSList *addr_list_iter; /* Points to address currently being used */ GIOChannel *GioCh; /* GIOChannel to monitor the connecting process */ gint Err; /* Holds the errno of the connect() call */ ChainLink *Info; /* Used for CCC asynchronous operations */} SocketData_t;/* * Local data */static Klist_t *ValidSocks = NULL; /* Active sockets list. It holds pointers to * SocketData_t structures. */static DilloUrl *HTTP_Proxy = NULL;static gchar *HTTP_Proxy_Auth_base64 = NULL;/* * Initialize proxy vars. */gint a_Http_init(void){ gchar *env_proxy = getenv("http_proxy"); if (env_proxy && strlen(env_proxy)) HTTP_Proxy = a_Url_new(env_proxy, NULL, 0, 0, 0); if (!HTTP_Proxy && prefs.http_proxy) HTTP_Proxy = a_Url_dup(prefs.http_proxy);/* This allows for storing the proxy password in "user:passwd" format * in dillorc, but as this constitutes a security problem, it was disabled. * if (HTTP_Proxy && prefs.http_proxyuser && strchr(prefs.http_proxyuser, ':')) HTTP_Proxy_Auth_base64 = a_Misc_encode_base64(prefs.http_proxyuser); */ return 0;}/* * Tell whether the proxy auth is already set (user:password) * Return: 1 Yes, 0 No */gint a_Http_proxy_auth(void){ return (HTTP_Proxy_Auth_base64 ? 1 : 0);}/* * Activate entered proxy password for HTTP. */void a_Http_set_proxy_passwd(gchar *str){ gchar *http_proxyauth = g_strconcat(prefs.http_proxyuser, ":", str, NULL); HTTP_Proxy_Auth_base64 = a_Misc_encode_base64(http_proxyauth); g_free(http_proxyauth);}/* * Forward declarations */static void Http_send_query(ChainLink *Info, SocketData_t *S);static int Http_connect_socket(ChainLink *Info);/* * Create and init a new SocketData_t struct, insert into ValidSocks, * and return a primary key for it. */static gint Http_sock_new(void){ SocketData_t *S = g_new0(SocketData_t, 1); return a_Klist_insert(&ValidSocks, (gpointer)S);}/* * Free SocketData_t struct */static void Http_socket_free(gint SKey){ SocketData_t *S; if ((S = a_Klist_get_data(ValidSocks, SKey))) { a_Klist_remove(ValidSocks, SKey); if (S->GioCh) g_io_channel_unref(S->GioCh); g_free(S); }}/* * Make the http query string */gchar *a_Http_make_query_str(const DilloUrl *url, gboolean use_proxy){ gchar *str, *ptr, *cookies; GString *s_port = g_string_new(""), *query = g_string_new(""), *full_path = g_string_new(""), *proxy_auth = g_string_new(""); /* Sending the default port in the query may cause a 302-answer. --Jcid */ if (URL_PORT(url) && URL_PORT(url) != DILLO_URL_HTTP_PORT) g_string_sprintfa(s_port, ":%d", URL_PORT(url)); if (use_proxy) { g_string_sprintfa(full_path, "%s%s", URL_STR(url), (URL_PATH_(url) || URL_QUERY_(url)) ? "" : "/"); if ((ptr = strrchr(full_path->str, '#'))) g_string_truncate(full_path, ptr - full_path->str); if (HTTP_Proxy_Auth_base64) g_string_sprintf(proxy_auth, "Proxy-Authorization: Basic %s\r\n", HTTP_Proxy_Auth_base64); } else { g_string_sprintfa(full_path, "%s%s%s%s", URL_PATH(url), URL_QUERY_(url) ? "?" : "", URL_QUERY(url), (URL_PATH_(url) || URL_QUERY_(url)) ? "" : "/"); } cookies = a_Cookies_get(url); if ( URL_FLAGS(url) & URL_Post ){ g_string_sprintfa( query, "POST %s HTTP/1.0\r\n" "Host: %s%s\r\n" "%s" "User-Agent: Dillo/%s\r\n" "Cookie2: $Version=\"1\"\r\n" "%s" "Content-type: application/x-www-form-urlencoded\r\n" "Content-length: %ld\r\n" "\r\n" "%s", full_path->str, URL_HOST(url), s_port->str, proxy_auth->str, VERSION, cookies, (glong)strlen(URL_DATA(url)), URL_DATA(url)); } else { g_string_sprintfa( query, "GET %s HTTP/1.0\r\n" "%s" "Host: %s%s\r\n" "%s" "User-Agent: Dillo/%s\r\n" "Cookie2: $Version=\"1\"\r\n" "%s" "\r\n", full_path->str, (URL_FLAGS(url) & URL_E2EReload) ? "Cache-Control: no-cache\r\nPragma: no-cache\r\n" : "", URL_HOST(url), s_port->str, proxy_auth->str, VERSION, cookies); } g_free(cookies); str = query->str; g_string_free(query, FALSE); g_string_free(s_port, TRUE); g_string_free(full_path, TRUE); g_string_free(proxy_auth, TRUE); DEBUG_MSG(4, "Query:\n%s", str); return str;}/* * This function is called after the socket has been successfuly connected, * or upon an error condition on the connecting process. * Task: use the socket to send the HTTP-query and expect its answer */static gboolean Http_use_socket(GIOChannel *src, GIOCondition cond, gpointer data){ ChainLink *Info; SocketData_t *S; gint SKey = GPOINTER_TO_INT(data); DEBUG_MSG(3, "Http_use_socket: %s [errno %d] [GIOcond %d]\n", g_strerror(errno), errno, cond); /* This check is required because glib may asynchronously * call this function with data that's no longer used --Jcid */ if ( !(S = a_Klist_get_data(ValidSocks, SKey)) ) return FALSE; Info = S->Info; if ( cond & G_IO_HUP ) { DEBUG_MSG(3, "--Connection broken\n"); /* get rid of S->GioCh */ g_io_channel_close(S->GioCh); g_io_channel_unref(S->GioCh); S->GioCh = NULL; if (S->addr_list_iter->next) { S->addr_list_iter = S->addr_list_iter->next; if (Http_connect_socket(Info) < 0) { BW_MSG(S->web, 0, "ERROR: unable to connect to remote host"); Http_socket_free(SKey); a_Chain_fcb(OpAbort, Info, NULL, NULL); } } } else if ( S->Err ) { BW_MSG(S->web, 0, "ERROR: %s", g_strerror(S->Err)); DEBUG_MSG(3, "Http_use_socket ERROR: %s\n", g_strerror(S->Err)); a_Chain_fcb(OpAbort, Info, NULL, NULL); g_io_channel_close(S->GioCh); Http_socket_free(SKey); } else if ( cond & G_IO_OUT ) { DEBUG_MSG(3, "--Connection established\n"); g_io_channel_unref(S->GioCh); S->GioCh = NULL; Http_send_query(Info, S); } return FALSE;}/* * This function gets called after the DNS succeeds solving a hostname. * Task: Finish socket setup and start connecting the socket. * Return value: 0 on success; -1 on error. */static int Http_connect_socket(ChainLink *Info){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -