00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "includes.h"
00016 #include <fcntl.h>
00017
00018 #include "common.h"
00019 #include "eloop.h"
00020 #include "httpread.h"
00021 #include "http_client.h"
00022
00023
00024 #define HTTP_CLIENT_TIMEOUT 30
00025
00026
00027 struct http_client {
00028 struct sockaddr_in dst;
00029 int sd;
00030 struct wpabuf *req;
00031 size_t req_pos;
00032 size_t max_response;
00033
00034 void (*cb)(void *ctx, struct http_client *c,
00035 enum http_client_event event);
00036 void *cb_ctx;
00037 struct httpread *hread;
00038 struct wpabuf body;
00039 };
00040
00041
00042 static void http_client_timeout(void *eloop_data, void *user_ctx)
00043 {
00044 struct http_client *c = eloop_data;
00045 wpa_printf(MSG_DEBUG, "HTTP: Timeout");
00046 c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
00047 }
00048
00049
00050 static void http_client_got_response(struct httpread *handle, void *cookie,
00051 enum httpread_event e)
00052 {
00053 struct http_client *c = cookie;
00054
00055 eloop_cancel_timeout(http_client_timeout, c, NULL);
00056 switch (e) {
00057 case HTTPREAD_EVENT_FILE_READY:
00058 if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY)
00059 {
00060 int reply_code = httpread_reply_code_get(c->hread);
00061 if (reply_code == 200 ) {
00062 wpa_printf(MSG_DEBUG, "HTTP: Response OK from "
00063 "%s:%d",
00064 inet_ntoa(c->dst.sin_addr),
00065 ntohs(c->dst.sin_port));
00066 c->cb(c->cb_ctx, c, HTTP_CLIENT_OK);
00067 } else {
00068 wpa_printf(MSG_DEBUG, "HTTP: Error %d from "
00069 "%s:%d", reply_code,
00070 inet_ntoa(c->dst.sin_addr),
00071 ntohs(c->dst.sin_port));
00072 c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
00073 }
00074 } else
00075 c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
00076 break;
00077 case HTTPREAD_EVENT_TIMEOUT:
00078 c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
00079 break;
00080 case HTTPREAD_EVENT_ERROR:
00081 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
00082 break;
00083 }
00084 }
00085
00086
00087 static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
00088 {
00089 struct http_client *c = eloop_ctx;
00090 int res;
00091
00092 wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu "
00093 "bytes remaining)",
00094 inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port),
00095 (unsigned long) wpabuf_len(c->req),
00096 (unsigned long) wpabuf_len(c->req) - c->req_pos);
00097
00098 res = send(c->sd, wpabuf_head(c->req) + c->req_pos,
00099 wpabuf_len(c->req) - c->req_pos, 0);
00100 if (res < 0) {
00101 wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s",
00102 strerror(errno));
00103 eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
00104 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
00105 return;
00106 }
00107
00108 if ((size_t) res < wpabuf_len(c->req) - c->req_pos) {
00109 wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes "
00110 "remaining",
00111 res, (unsigned long) wpabuf_len(c->req),
00112 (unsigned long) wpabuf_len(c->req) - c->req_pos -
00113 res);
00114 c->req_pos += res;
00115 return;
00116 }
00117
00118 wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d",
00119 inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port));
00120 eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
00121 wpabuf_free(c->req);
00122 c->req = NULL;
00123
00124 c->hread = httpread_create(c->sd, http_client_got_response, c,
00125 c->max_response, HTTP_CLIENT_TIMEOUT);
00126 if (c->hread == NULL) {
00127 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
00128 return;
00129 }
00130 }
00131
00132
00133 struct http_client * http_client_addr(struct sockaddr_in *dst,
00134 struct wpabuf *req, size_t max_response,
00135 void (*cb)(void *ctx,
00136 struct http_client *c,
00137 enum http_client_event event),
00138 void *cb_ctx)
00139 {
00140 struct http_client *c;
00141
00142 c = os_zalloc(sizeof(*c));
00143 if (c == NULL)
00144 return NULL;
00145 c->sd = -1;
00146 c->dst = *dst;
00147 c->max_response = max_response;
00148 c->cb = cb;
00149 c->cb_ctx = cb_ctx;
00150
00151 c->sd = socket(AF_INET, SOCK_STREAM, 0);
00152 if (c->sd < 0) {
00153 http_client_free(c);
00154 return NULL;
00155 }
00156
00157 if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) {
00158 wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s",
00159 strerror(errno));
00160 http_client_free(c);
00161 return NULL;
00162 }
00163
00164 if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) {
00165 if (errno != EINPROGRESS) {
00166 wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s",
00167 strerror(errno));
00168 http_client_free(c);
00169 return NULL;
00170 }
00171
00172
00173
00174
00175
00176 }
00177
00178 if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready,
00179 c, NULL)) {
00180 http_client_free(c);
00181 return NULL;
00182 }
00183
00184 if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT, 0, http_client_timeout,
00185 c, NULL)) {
00186 http_client_free(c);
00187 return NULL;
00188 }
00189
00190 c->req = req;
00191
00192 return c;
00193 }
00194
00195
00196 char * http_client_url_parse(const char *url, struct sockaddr_in *dst,
00197 char **ret_path)
00198 {
00199 char *u, *addr, *port, *path;
00200
00201 u = os_strdup(url);
00202 if (u == NULL)
00203 return NULL;
00204
00205 os_memset(dst, 0, sizeof(*dst));
00206 dst->sin_family = AF_INET;
00207 addr = u + 7;
00208 path = os_strchr(addr, '/');
00209 port = os_strchr(addr, ':');
00210 if (path == NULL) {
00211 path = "/";
00212 } else {
00213 *path = '\0';
00214 if (port > path)
00215 port = NULL;
00216 }
00217 if (port)
00218 *port++ = '\0';
00219
00220 if (inet_aton(addr, &dst->sin_addr) == 0) {
00221
00222 wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' "
00223 "(addr='%s' port='%s')",
00224 url, addr, port);
00225 os_free(u);
00226 return NULL;
00227 }
00228
00229 if (port)
00230 dst->sin_port = htons(atoi(port));
00231 else
00232 dst->sin_port = htons(80);
00233
00234 if (*path == '\0') {
00235
00236 *path = '/';
00237 }
00238
00239 *ret_path = path;
00240
00241 return u;
00242 }
00243
00244
00245 struct http_client * http_client_url(const char *url,
00246 struct wpabuf *req, size_t max_response,
00247 void (*cb)(void *ctx,
00248 struct http_client *c,
00249 enum http_client_event event),
00250 void *cb_ctx)
00251 {
00252 struct sockaddr_in dst;
00253 struct http_client *c;
00254 char *u, *path;
00255 struct wpabuf *req_buf = NULL;
00256
00257 if (os_strncmp(url, "http://", 7) != 0)
00258 return NULL;
00259 u = http_client_url_parse(url, &dst, &path);
00260 if (u == NULL)
00261 return NULL;
00262
00263 if (req == NULL) {
00264 req_buf = wpabuf_alloc(os_strlen(url) + 1000);
00265 if (req_buf == NULL) {
00266 os_free(u);
00267 return NULL;
00268 }
00269 req = req_buf;
00270 wpabuf_printf(req,
00271 "GET %s HTTP/1.1\r\n"
00272 "Cache-Control: no-cache\r\n"
00273 "Pragma: no-cache\r\n"
00274 "Accept: text/xml, application/xml\r\n"
00275 "User-Agent: wpa_supplicant\r\n"
00276 "Host: %s:%d\r\n"
00277 "\r\n",
00278 path, inet_ntoa(dst.sin_addr),
00279 ntohs(dst.sin_port));
00280 }
00281 os_free(u);
00282
00283 c = http_client_addr(&dst, req, max_response, cb, cb_ctx);
00284 if (c == NULL) {
00285 wpabuf_free(req_buf);
00286 return NULL;
00287 }
00288
00289 return c;
00290 }
00291
00292
00293 void http_client_free(struct http_client *c)
00294 {
00295 if (c == NULL)
00296 return;
00297 httpread_destroy(c->hread);
00298 wpabuf_free(c->req);
00299 if (c->sd >= 0) {
00300 eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
00301 close(c->sd);
00302 }
00303 eloop_cancel_timeout(http_client_timeout, c, NULL);
00304 os_free(c);
00305 }
00306
00307
00308 struct wpabuf * http_client_get_body(struct http_client *c)
00309 {
00310 if (c->hread == NULL)
00311 return NULL;
00312 wpabuf_set(&c->body, httpread_data_get(c->hread),
00313 httpread_length_get(c->hread));
00314 return &c->body;
00315 }
00316
00317
00318 char * http_client_get_hdr_line(struct http_client *c, const char *tag)
00319 {
00320 if (c->hread == NULL)
00321 return NULL;
00322 return httpread_hdr_line_get(c->hread, tag);
00323 }
00324
00325
00326 char * http_link_update(char *url, const char *base)
00327 {
00328 char *n;
00329 size_t len;
00330 const char *pos;
00331
00332
00333
00334
00335 if (url == NULL)
00336 return NULL;
00337
00338 if (os_strncmp(url, "http://", 7) == 0)
00339 return url;
00340
00341 if (os_strncmp(base, "http://", 7) != 0)
00342 return url;
00343
00344 len = os_strlen(url) + 1 + os_strlen(base) + 1;
00345 n = os_malloc(len);
00346 if (n == NULL)
00347 return url;
00348
00349 if (url[0] == '/') {
00350 pos = os_strchr(base + 7, '/');
00351 if (pos == NULL) {
00352 os_snprintf(n, len, "%s%s", base, url);
00353 } else {
00354 os_memcpy(n, base, pos - base);
00355 os_memcpy(n + (pos - base), url, os_strlen(url) + 1);
00356 }
00357 } else {
00358 pos = os_strrchr(base + 7, '/');
00359 if (pos == NULL) {
00360 os_snprintf(n, len, "%s/%s", base, url);
00361 } else {
00362 os_memcpy(n, base, pos - base + 1);
00363 os_memcpy(n + (pos - base) + 1, url, os_strlen(url) +
00364 1);
00365 }
00366 }
00367
00368 os_free(url);
00369
00370 return n;
00371 }