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