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