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