2 * http_client - HTTP client
3 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
21 #include "http_client.h"
24 #define HTTP_CLIENT_TIMEOUT 30
28 struct sockaddr_in dst
;
34 void (*cb
)(void *ctx
, struct http_client
*c
,
35 enum http_client_event event
);
37 struct httpread
*hread
;
42 static void http_client_timeout(void *eloop_data
, void *user_ctx
)
44 struct http_client
*c
= eloop_data
;
45 wpa_printf(MSG_DEBUG
, "HTTP: Timeout");
46 c
->cb(c
->cb_ctx
, c
, HTTP_CLIENT_TIMEOUT
);
50 static void http_client_got_response(struct httpread
*handle
, void *cookie
,
51 enum httpread_event e
)
53 struct http_client
*c
= cookie
;
55 eloop_cancel_timeout(http_client_timeout
, c
, NULL
);
57 case HTTPREAD_EVENT_FILE_READY
:
58 if (httpread_hdr_type_get(c
->hread
) == HTTPREAD_HDR_TYPE_REPLY
)
60 int reply_code
= httpread_reply_code_get(c
->hread
);
61 if (reply_code
== 200 /* OK */) {
62 wpa_printf(MSG_DEBUG
, "HTTP: Response OK from "
64 inet_ntoa(c
->dst
.sin_addr
),
65 ntohs(c
->dst
.sin_port
));
66 c
->cb(c
->cb_ctx
, c
, HTTP_CLIENT_OK
);
68 wpa_printf(MSG_DEBUG
, "HTTP: Error %d from "
70 inet_ntoa(c
->dst
.sin_addr
),
71 ntohs(c
->dst
.sin_port
));
72 c
->cb(c
->cb_ctx
, c
, HTTP_CLIENT_INVALID_REPLY
);
75 c
->cb(c
->cb_ctx
, c
, HTTP_CLIENT_INVALID_REPLY
);
77 case HTTPREAD_EVENT_TIMEOUT
:
78 c
->cb(c
->cb_ctx
, c
, HTTP_CLIENT_TIMEOUT
);
80 case HTTPREAD_EVENT_ERROR
:
81 c
->cb(c
->cb_ctx
, c
, HTTP_CLIENT_FAILED
);
87 static void http_client_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
89 struct http_client
*c
= eloop_ctx
;
92 wpa_printf(MSG_DEBUG
, "HTTP: Send client request to %s:%d (%lu of %lu "
94 inet_ntoa(c
->dst
.sin_addr
), ntohs(c
->dst
.sin_port
),
95 (unsigned long) wpabuf_len(c
->req
),
96 (unsigned long) wpabuf_len(c
->req
) - c
->req_pos
);
98 res
= send(c
->sd
, wpabuf_head(c
->req
) + c
->req_pos
,
99 wpabuf_len(c
->req
) - c
->req_pos
, 0);
101 wpa_printf(MSG_DEBUG
, "HTTP: Failed to send buffer: %s",
103 eloop_unregister_sock(c
->sd
, EVENT_TYPE_WRITE
);
104 c
->cb(c
->cb_ctx
, c
, HTTP_CLIENT_FAILED
);
108 if ((size_t) res
< wpabuf_len(c
->req
) - c
->req_pos
) {
109 wpa_printf(MSG_DEBUG
, "HTTP: Sent %d of %lu bytes; %lu bytes "
111 res
, (unsigned long) wpabuf_len(c
->req
),
112 (unsigned long) wpabuf_len(c
->req
) - c
->req_pos
-
118 wpa_printf(MSG_DEBUG
, "HTTP: Full client request sent to %s:%d",
119 inet_ntoa(c
->dst
.sin_addr
), ntohs(c
->dst
.sin_port
));
120 eloop_unregister_sock(c
->sd
, EVENT_TYPE_WRITE
);
124 c
->hread
= httpread_create(c
->sd
, http_client_got_response
, c
,
125 c
->max_response
, HTTP_CLIENT_TIMEOUT
);
126 if (c
->hread
== NULL
) {
127 c
->cb(c
->cb_ctx
, c
, HTTP_CLIENT_FAILED
);
133 struct http_client
* http_client_addr(struct sockaddr_in
*dst
,
134 struct wpabuf
*req
, size_t max_response
,
135 void (*cb
)(void *ctx
,
136 struct http_client
*c
,
137 enum http_client_event event
),
140 struct http_client
*c
;
142 c
= os_zalloc(sizeof(*c
));
147 c
->max_response
= max_response
;
151 c
->sd
= socket(AF_INET
, SOCK_STREAM
, 0);
157 if (fcntl(c
->sd
, F_SETFL
, O_NONBLOCK
) != 0) {
158 wpa_printf(MSG_DEBUG
, "HTTP: fnctl(O_NONBLOCK) failed: %s",
164 if (connect(c
->sd
, (struct sockaddr
*) dst
, sizeof(*dst
))) {
165 if (errno
!= EINPROGRESS
) {
166 wpa_printf(MSG_DEBUG
, "HTTP: Failed to connect: %s",
173 * Continue connecting in the background; eloop will call us
174 * once the connection is ready (or failed).
178 if (eloop_register_sock(c
->sd
, EVENT_TYPE_WRITE
, http_client_tx_ready
,
184 if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT
, 0, http_client_timeout
,
196 char * http_client_url_parse(const char *url
, struct sockaddr_in
*dst
,
199 char *u
, *addr
, *port
, *path
;
205 os_memset(dst
, 0, sizeof(*dst
));
206 dst
->sin_family
= AF_INET
;
208 path
= os_strchr(addr
, '/');
209 port
= os_strchr(addr
, ':');
213 *path
= '\0'; /* temporary nul termination for address */
220 if (inet_aton(addr
, &dst
->sin_addr
) == 0) {
221 /* TODO: name lookup */
222 wpa_printf(MSG_DEBUG
, "HTTP: Unsupported address in URL '%s' "
223 "(addr='%s' port='%s')",
230 dst
->sin_port
= htons(atoi(port
));
232 dst
->sin_port
= htons(80);
235 /* remove temporary nul termination for address */
245 struct http_client
* http_client_url(const char *url
,
246 struct wpabuf
*req
, size_t max_response
,
247 void (*cb
)(void *ctx
,
248 struct http_client
*c
,
249 enum http_client_event event
),
252 struct sockaddr_in dst
;
253 struct http_client
*c
;
255 struct wpabuf
*req_buf
= NULL
;
257 if (os_strncmp(url
, "http://", 7) != 0)
259 u
= http_client_url_parse(url
, &dst
, &path
);
264 req_buf
= wpabuf_alloc(os_strlen(url
) + 1000);
265 if (req_buf
== NULL
) {
271 "GET %s HTTP/1.1\r\n"
272 "Cache-Control: no-cache\r\n"
273 "Pragma: no-cache\r\n"
274 "Accept: text/xml, application/xml\r\n"
275 "User-Agent: wpa_supplicant\r\n"
278 path
, inet_ntoa(dst
.sin_addr
),
279 ntohs(dst
.sin_port
));
283 c
= http_client_addr(&dst
, req
, max_response
, cb
, cb_ctx
);
285 wpabuf_free(req_buf
);
293 void http_client_free(struct http_client
*c
)
297 httpread_destroy(c
->hread
);
300 eloop_unregister_sock(c
->sd
, EVENT_TYPE_WRITE
);
303 eloop_cancel_timeout(http_client_timeout
, c
, NULL
);
308 struct wpabuf
* http_client_get_body(struct http_client
*c
)
310 if (c
->hread
== NULL
)
312 wpabuf_set(&c
->body
, httpread_data_get(c
->hread
),
313 httpread_length_get(c
->hread
));
318 char * http_client_get_hdr_line(struct http_client
*c
, const char *tag
)
320 if (c
->hread
== NULL
)
322 return httpread_hdr_line_get(c
->hread
, tag
);
326 char * http_link_update(char *url
, const char *base
)
332 /* RFC 2396, Chapter 5.2 */
333 /* TODO: consider adding all cases described in RFC 2396 */
338 if (os_strncmp(url
, "http://", 7) == 0)
339 return url
; /* absolute link */
341 if (os_strncmp(base
, "http://", 7) != 0)
342 return url
; /* unable to handle base URL */
344 len
= os_strlen(url
) + 1 + os_strlen(base
) + 1;
347 return url
; /* failed */
350 pos
= os_strchr(base
+ 7, '/');
352 os_snprintf(n
, len
, "%s%s", base
, url
);
354 os_memcpy(n
, base
, pos
- base
);
355 os_memcpy(n
+ (pos
- base
), url
, os_strlen(url
) + 1);
358 pos
= os_strrchr(base
+ 7, '/');
360 os_snprintf(n
, len
, "%s/%s", base
, url
);
362 os_memcpy(n
, base
, pos
- base
+ 1);
363 os_memcpy(n
+ (pos
- base
) + 1, url
, os_strlen(url
) +