18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * http_client - HTTP client
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <fcntl.h>
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "httpread.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "http_client.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define HTTP_CLIENT_TIMEOUT_SEC 30
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct http_client {
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in dst;
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int sd;
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *req;
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t req_pos;
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t max_response;
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*cb)(void *ctx, struct http_client *c,
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   enum http_client_event event);
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *cb_ctx;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct httpread *hread;
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf body;
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void http_client_timeout(void *eloop_data, void *user_ctx)
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct http_client *c = eloop_data;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "HTTP: Timeout (c=%p)", c);
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void http_client_got_response(struct httpread *handle, void *cookie,
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     enum httpread_event e)
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct http_client *c = cookie;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "HTTP: httpread callback: handle=%p cookie=%p "
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "e=%d", handle, cookie, e);
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(http_client_timeout, c, NULL);
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (e) {
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTPREAD_EVENT_FILE_READY:
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY)
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int reply_code = httpread_reply_code_get(c->hread);
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (reply_code == 200 /* OK */) {
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "HTTP: Response OK from "
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "%s:%d",
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   inet_ntoa(c->dst.sin_addr),
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   ntohs(c->dst.sin_port));
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				c->cb(c->cb_ctx, c, HTTP_CLIENT_OK);
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			} else {
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "HTTP: Error %d from "
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "%s:%d", reply_code,
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   inet_ntoa(c->dst.sin_addr),
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   ntohs(c->dst.sin_port));
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTPREAD_EVENT_TIMEOUT:
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTPREAD_EVENT_ERROR:
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct http_client *c = eloop_ctx;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu "
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "bytes remaining)",
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port),
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) wpabuf_len(c->req),
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) wpabuf_len(c->req) - c->req_pos);
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9551b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt	res = send(c->sd, wpabuf_head_u8(c->req) + c->req_pos,
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   wpabuf_len(c->req) - c->req_pos, 0);
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s",
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   strerror(errno));
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((size_t) res < wpabuf_len(c->req) - c->req_pos) {
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes "
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "remaining",
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   res, (unsigned long) wpabuf_len(c->req),
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) wpabuf_len(c->req) - c->req_pos -
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   res);
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		c->req_pos += res;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d",
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port));
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(c->req);
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->req = NULL;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->hread = httpread_create(c->sd, http_client_got_response, c,
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   c->max_response, HTTP_CLIENT_TIMEOUT_SEC);
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (c->hread == NULL) {
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct http_client * http_client_addr(struct sockaddr_in *dst,
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      struct wpabuf *req, size_t max_response,
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      void (*cb)(void *ctx,
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct http_client *c,
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 enum http_client_event event),
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      void *cb_ctx)
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct http_client *c;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c = os_zalloc(sizeof(*c));
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (c == NULL)
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->sd = -1;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->dst = *dst;
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->max_response = max_response;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->cb = cb;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->cb_ctx = cb_ctx;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->sd = socket(AF_INET, SOCK_STREAM, 0);
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (c->sd < 0) {
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		http_client_free(c);
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) {
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s",
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   strerror(errno));
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		http_client_free(c);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) {
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (errno != EINPROGRESS) {
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s",
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   strerror(errno));
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			http_client_free(c);
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Continue connecting in the background; eloop will call us
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * once the connection is ready (or failed).
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready,
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				c, NULL)) {
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		http_client_free(c);
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT_SEC, 0,
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   http_client_timeout, c, NULL)) {
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		http_client_free(c);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c->req = req;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return c;
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * http_client_url_parse(const char *url, struct sockaddr_in *dst,
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     char **ret_path)
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *u, *addr, *port, *path;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u = os_strdup(url);
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (u == NULL)
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(dst, 0, sizeof(*dst));
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->sin_family = AF_INET;
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr = u + 7;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	path = os_strchr(addr, '/');
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	port = os_strchr(addr, ':');
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (path == NULL) {
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		path = "/";
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*path = '\0'; /* temporary nul termination for address */
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (port > path)
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			port = NULL;
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (port)
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*port++ = '\0';
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (inet_aton(addr, &dst->sin_addr) == 0) {
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: name lookup */
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' "
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(addr='%s' port='%s')",
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   url, addr, port);
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(u);
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (port)
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dst->sin_port = htons(atoi(port));
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dst->sin_port = htons(80);
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (*path == '\0') {
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* remove temporary nul termination for address */
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*path = '/';
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ret_path = path;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return u;
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct http_client * http_client_url(const char *url,
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct wpabuf *req, size_t max_response,
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     void (*cb)(void *ctx,
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct http_client *c,
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						enum http_client_event event),
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     void *cb_ctx)
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in dst;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct http_client *c;
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *u, *path;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *req_buf = NULL;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strncmp(url, "http://", 7) != 0)
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u = http_client_url_parse(url, &dst, &path);
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (u == NULL)
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req == NULL) {
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		req_buf = wpabuf_alloc(os_strlen(url) + 1000);
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (req_buf == NULL) {
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(u);
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		req = req_buf;
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_printf(req,
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      "GET %s HTTP/1.1\r\n"
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      "Cache-Control: no-cache\r\n"
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      "Pragma: no-cache\r\n"
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      "Accept: text/xml, application/xml\r\n"
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      "User-Agent: wpa_supplicant\r\n"
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      "Host: %s:%d\r\n"
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      "\r\n",
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      path, inet_ntoa(dst.sin_addr),
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      ntohs(dst.sin_port));
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(u);
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	c = http_client_addr(&dst, req, max_response, cb, cb_ctx);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (c == NULL) {
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(req_buf);
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return c;
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid http_client_free(struct http_client *c)
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (c == NULL)
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	httpread_destroy(c->hread);
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(c->req);
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (c->sd >= 0) {
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(c->sd);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(http_client_timeout, c, NULL);
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(c);
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * http_client_get_body(struct http_client *c)
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (c->hread == NULL)
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_set(&c->body, httpread_data_get(c->hread),
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   httpread_length_get(c->hread));
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return &c->body;
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * http_client_get_hdr_line(struct http_client *c, const char *tag)
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (c->hread == NULL)
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return httpread_hdr_line_get(c->hread, tag);
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * http_link_update(char *url, const char *base)
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *n;
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *pos;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* RFC 2396, Chapter 5.2 */
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: consider adding all cases described in RFC 2396 */
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (url == NULL)
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strncmp(url, "http://", 7) == 0)
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return url; /* absolute link */
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strncmp(base, "http://", 7) != 0)
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return url; /* unable to handle base URL */
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = os_strlen(url) + 1 + os_strlen(base) + 1;
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	n = os_malloc(len);
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (n == NULL)
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return url; /* failed */
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (url[0] == '/') {
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = os_strchr(base + 7, '/');
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos == NULL) {
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_snprintf(n, len, "%s%s", base, url);
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(n, base, pos - base);
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(n + (pos - base), url, os_strlen(url) + 1);
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = os_strrchr(base + 7, '/');
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos == NULL) {
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_snprintf(n, len, "%s/%s", base, url);
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(n, base, pos - base + 1);
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(n + (pos - base) + 1, url, os_strlen(url) +
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  1);
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(url);
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return n;
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
369