LCOV - code coverage report
Current view: top level - src/wps - http_client.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1393793999 Lines: 124 180 68.9 %
Date: 2014-03-02 Functions: 9 10 90.0 %
Branches: 38 74 51.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * http_client - HTTP client
       3                 :            :  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
       4                 :            :  *
       5                 :            :  * This software may be distributed under the terms of the BSD license.
       6                 :            :  * See README for more details.
       7                 :            :  */
       8                 :            : 
       9                 :            : #include "includes.h"
      10                 :            : #include <fcntl.h>
      11                 :            : 
      12                 :            : #include "common.h"
      13                 :            : #include "eloop.h"
      14                 :            : #include "httpread.h"
      15                 :            : #include "http_client.h"
      16                 :            : 
      17                 :            : 
      18                 :            : #define HTTP_CLIENT_TIMEOUT_SEC 30
      19                 :            : 
      20                 :            : 
      21                 :            : struct http_client {
      22                 :            :         struct sockaddr_in dst;
      23                 :            :         int sd;
      24                 :            :         struct wpabuf *req;
      25                 :            :         size_t req_pos;
      26                 :            :         size_t max_response;
      27                 :            : 
      28                 :            :         void (*cb)(void *ctx, struct http_client *c,
      29                 :            :                    enum http_client_event event);
      30                 :            :         void *cb_ctx;
      31                 :            :         struct httpread *hread;
      32                 :            :         struct wpabuf body;
      33                 :            : };
      34                 :            : 
      35                 :            : 
      36                 :          0 : static void http_client_timeout(void *eloop_data, void *user_ctx)
      37                 :            : {
      38                 :          0 :         struct http_client *c = eloop_data;
      39                 :          0 :         wpa_printf(MSG_DEBUG, "HTTP: Timeout (c=%p)", c);
      40                 :          0 :         c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
      41                 :          0 : }
      42                 :            : 
      43                 :            : 
      44                 :        141 : static void http_client_got_response(struct httpread *handle, void *cookie,
      45                 :            :                                      enum httpread_event e)
      46                 :            : {
      47                 :        141 :         struct http_client *c = cookie;
      48                 :            : 
      49                 :        141 :         wpa_printf(MSG_DEBUG, "HTTP: httpread callback: handle=%p cookie=%p "
      50                 :            :                    "e=%d", handle, cookie, e);
      51                 :            : 
      52                 :        141 :         eloop_cancel_timeout(http_client_timeout, c, NULL);
      53   [ +  -  -  - ]:        141 :         switch (e) {
      54                 :            :         case HTTPREAD_EVENT_FILE_READY:
      55         [ +  - ]:        141 :                 if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY)
      56                 :            :                 {
      57                 :        141 :                         int reply_code = httpread_reply_code_get(c->hread);
      58         [ +  + ]:        141 :                         if (reply_code == 200 /* OK */) {
      59                 :        140 :                                 wpa_printf(MSG_DEBUG, "HTTP: Response OK from "
      60                 :            :                                            "%s:%d",
      61                 :            :                                            inet_ntoa(c->dst.sin_addr),
      62                 :        140 :                                            ntohs(c->dst.sin_port));
      63                 :        140 :                                 c->cb(c->cb_ctx, c, HTTP_CLIENT_OK);
      64                 :            :                         } else {
      65                 :          1 :                                 wpa_printf(MSG_DEBUG, "HTTP: Error %d from "
      66                 :            :                                            "%s:%d", reply_code,
      67                 :            :                                            inet_ntoa(c->dst.sin_addr),
      68                 :          1 :                                            ntohs(c->dst.sin_port));
      69                 :          1 :                                 c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
      70                 :            :                         }
      71                 :            :                 } else
      72                 :          0 :                         c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
      73                 :        141 :                 break;
      74                 :            :         case HTTPREAD_EVENT_TIMEOUT:
      75                 :          0 :                 c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
      76                 :          0 :                 break;
      77                 :            :         case HTTPREAD_EVENT_ERROR:
      78                 :          0 :                 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
      79                 :          0 :                 break;
      80                 :            :         }
      81                 :        141 : }
      82                 :            : 
      83                 :            : 
      84                 :        151 : static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
      85                 :            : {
      86                 :        151 :         struct http_client *c = eloop_ctx;
      87                 :            :         int res;
      88                 :            : 
      89                 :        302 :         wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu "
      90                 :            :                    "bytes remaining)",
      91                 :        151 :                    inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port),
      92                 :        151 :                    (unsigned long) wpabuf_len(c->req),
      93                 :        151 :                    (unsigned long) wpabuf_len(c->req) - c->req_pos);
      94                 :            : 
      95                 :        151 :         res = send(c->sd, wpabuf_head_u8(c->req) + c->req_pos,
      96                 :        151 :                    wpabuf_len(c->req) - c->req_pos, 0);
      97         [ +  + ]:        151 :         if (res < 0) {
      98                 :          9 :                 wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s",
      99                 :          9 :                            strerror(errno));
     100                 :          9 :                 eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
     101                 :          9 :                 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
     102                 :          9 :                 return;
     103                 :            :         }
     104                 :            : 
     105         [ -  + ]:        142 :         if ((size_t) res < wpabuf_len(c->req) - c->req_pos) {
     106                 :          0 :                 wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes "
     107                 :            :                            "remaining",
     108                 :          0 :                            res, (unsigned long) wpabuf_len(c->req),
     109                 :          0 :                            (unsigned long) wpabuf_len(c->req) - c->req_pos -
     110                 :            :                            res);
     111                 :          0 :                 c->req_pos += res;
     112                 :          0 :                 return;
     113                 :            :         }
     114                 :            : 
     115                 :        142 :         wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d",
     116                 :        142 :                    inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port));
     117                 :        142 :         eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
     118                 :        142 :         wpabuf_free(c->req);
     119                 :        142 :         c->req = NULL;
     120                 :            : 
     121                 :        142 :         c->hread = httpread_create(c->sd, http_client_got_response, c,
     122                 :        142 :                                    c->max_response, HTTP_CLIENT_TIMEOUT_SEC);
     123         [ -  + ]:        142 :         if (c->hread == NULL) {
     124                 :          0 :                 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
     125                 :        151 :                 return;
     126                 :            :         }
     127                 :            : }
     128                 :            : 
     129                 :            : 
     130                 :        152 : struct http_client * http_client_addr(struct sockaddr_in *dst,
     131                 :            :                                       struct wpabuf *req, size_t max_response,
     132                 :            :                                       void (*cb)(void *ctx,
     133                 :            :                                                  struct http_client *c,
     134                 :            :                                                  enum http_client_event event),
     135                 :            :                                       void *cb_ctx)
     136                 :            : {
     137                 :            :         struct http_client *c;
     138                 :            : 
     139                 :        152 :         c = os_zalloc(sizeof(*c));
     140         [ -  + ]:        152 :         if (c == NULL)
     141                 :          0 :                 return NULL;
     142                 :        152 :         c->sd = -1;
     143                 :        152 :         c->dst = *dst;
     144                 :        152 :         c->max_response = max_response;
     145                 :        152 :         c->cb = cb;
     146                 :        152 :         c->cb_ctx = cb_ctx;
     147                 :            : 
     148                 :        152 :         c->sd = socket(AF_INET, SOCK_STREAM, 0);
     149         [ -  + ]:        152 :         if (c->sd < 0) {
     150                 :          0 :                 http_client_free(c);
     151                 :          0 :                 return NULL;
     152                 :            :         }
     153                 :            : 
     154         [ -  + ]:        152 :         if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) {
     155                 :          0 :                 wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s",
     156                 :          0 :                            strerror(errno));
     157                 :          0 :                 http_client_free(c);
     158                 :          0 :                 return NULL;
     159                 :            :         }
     160                 :            : 
     161         [ +  - ]:        152 :         if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) {
     162         [ -  + ]:        152 :                 if (errno != EINPROGRESS) {
     163                 :          0 :                         wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s",
     164                 :          0 :                                    strerror(errno));
     165                 :          0 :                         http_client_free(c);
     166                 :          0 :                         return NULL;
     167                 :            :                 }
     168                 :            : 
     169                 :            :                 /*
     170                 :            :                  * Continue connecting in the background; eloop will call us
     171                 :            :                  * once the connection is ready (or failed).
     172                 :            :                  */
     173                 :            :         }
     174                 :            : 
     175         [ -  + ]:        152 :         if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready,
     176                 :            :                                 c, NULL)) {
     177                 :          0 :                 http_client_free(c);
     178                 :          0 :                 return NULL;
     179                 :            :         }
     180                 :            : 
     181         [ -  + ]:        152 :         if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT_SEC, 0,
     182                 :            :                                    http_client_timeout, c, NULL)) {
     183                 :          0 :                 http_client_free(c);
     184                 :          0 :                 return NULL;
     185                 :            :         }
     186                 :            : 
     187                 :        152 :         c->req = req;
     188                 :            : 
     189                 :        152 :         return c;
     190                 :            : }
     191                 :            : 
     192                 :            : 
     193                 :         88 : char * http_client_url_parse(const char *url, struct sockaddr_in *dst,
     194                 :            :                              char **ret_path)
     195                 :            : {
     196                 :            :         char *u, *addr, *port, *path;
     197                 :            : 
     198                 :         88 :         u = os_strdup(url);
     199         [ -  + ]:         88 :         if (u == NULL)
     200                 :          0 :                 return NULL;
     201                 :            : 
     202                 :         88 :         os_memset(dst, 0, sizeof(*dst));
     203                 :         88 :         dst->sin_family = AF_INET;
     204                 :         88 :         addr = u + 7;
     205                 :         88 :         path = os_strchr(addr, '/');
     206                 :         88 :         port = os_strchr(addr, ':');
     207         [ -  + ]:         88 :         if (path == NULL) {
     208                 :          0 :                 path = "/";
     209                 :            :         } else {
     210                 :         88 :                 *path = '\0'; /* temporary nul termination for address */
     211         [ -  + ]:         88 :                 if (port > path)
     212                 :          0 :                         port = NULL;
     213                 :            :         }
     214         [ +  - ]:         88 :         if (port)
     215                 :         88 :                 *port++ = '\0';
     216                 :            : 
     217         [ -  + ]:         88 :         if (inet_aton(addr, &dst->sin_addr) == 0) {
     218                 :            :                 /* TODO: name lookup */
     219                 :          0 :                 wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' "
     220                 :            :                            "(addr='%s' port='%s')",
     221                 :            :                            url, addr, port);
     222                 :          0 :                 os_free(u);
     223                 :          0 :                 return NULL;
     224                 :            :         }
     225                 :            : 
     226         [ +  - ]:         88 :         if (port)
     227                 :         88 :                 dst->sin_port = htons(atoi(port));
     228                 :            :         else
     229                 :          0 :                 dst->sin_port = htons(80);
     230                 :            : 
     231         [ +  - ]:         88 :         if (*path == '\0') {
     232                 :            :                 /* remove temporary nul termination for address */
     233                 :         88 :                 *path = '/';
     234                 :            :         }
     235                 :            : 
     236                 :         88 :         *ret_path = path;
     237                 :            : 
     238                 :         88 :         return u;
     239                 :            : }
     240                 :            : 
     241                 :            : 
     242                 :          9 : struct http_client * http_client_url(const char *url,
     243                 :            :                                      struct wpabuf *req, size_t max_response,
     244                 :            :                                      void (*cb)(void *ctx,
     245                 :            :                                                 struct http_client *c,
     246                 :            :                                                 enum http_client_event event),
     247                 :            :                                      void *cb_ctx)
     248                 :            : {
     249                 :            :         struct sockaddr_in dst;
     250                 :            :         struct http_client *c;
     251                 :            :         char *u, *path;
     252                 :          9 :         struct wpabuf *req_buf = NULL;
     253                 :            : 
     254         [ -  + ]:          9 :         if (os_strncmp(url, "http://", 7) != 0)
     255                 :          0 :                 return NULL;
     256                 :          9 :         u = http_client_url_parse(url, &dst, &path);
     257         [ -  + ]:          9 :         if (u == NULL)
     258                 :          0 :                 return NULL;
     259                 :            : 
     260         [ +  - ]:          9 :         if (req == NULL) {
     261                 :          9 :                 req_buf = wpabuf_alloc(os_strlen(url) + 1000);
     262         [ -  + ]:          9 :                 if (req_buf == NULL) {
     263                 :          0 :                         os_free(u);
     264                 :          0 :                         return NULL;
     265                 :            :                 }
     266                 :          9 :                 req = req_buf;
     267                 :          9 :                 wpabuf_printf(req,
     268                 :            :                               "GET %s HTTP/1.1\r\n"
     269                 :            :                               "Cache-Control: no-cache\r\n"
     270                 :            :                               "Pragma: no-cache\r\n"
     271                 :            :                               "Accept: text/xml, application/xml\r\n"
     272                 :            :                               "User-Agent: wpa_supplicant\r\n"
     273                 :            :                               "Host: %s:%d\r\n"
     274                 :            :                               "\r\n",
     275                 :            :                               path, inet_ntoa(dst.sin_addr),
     276                 :          9 :                               ntohs(dst.sin_port));
     277                 :            :         }
     278                 :          9 :         os_free(u);
     279                 :            : 
     280                 :          9 :         c = http_client_addr(&dst, req, max_response, cb, cb_ctx);
     281         [ -  + ]:          9 :         if (c == NULL) {
     282                 :          0 :                 wpabuf_free(req_buf);
     283                 :          0 :                 return NULL;
     284                 :            :         }
     285                 :            : 
     286                 :          9 :         return c;
     287                 :            : }
     288                 :            : 
     289                 :            : 
     290                 :        188 : void http_client_free(struct http_client *c)
     291                 :            : {
     292         [ +  + ]:        188 :         if (c == NULL)
     293                 :        188 :                 return;
     294                 :        152 :         httpread_destroy(c->hread);
     295                 :        152 :         wpabuf_free(c->req);
     296         [ +  - ]:        152 :         if (c->sd >= 0) {
     297                 :        152 :                 eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
     298                 :        152 :                 close(c->sd);
     299                 :            :         }
     300                 :        152 :         eloop_cancel_timeout(http_client_timeout, c, NULL);
     301                 :        152 :         os_free(c);
     302                 :            : }
     303                 :            : 
     304                 :            : 
     305                 :         27 : struct wpabuf * http_client_get_body(struct http_client *c)
     306                 :            : {
     307         [ -  + ]:         27 :         if (c->hread == NULL)
     308                 :          0 :                 return NULL;
     309                 :         27 :         wpabuf_set(&c->body, httpread_data_get(c->hread),
     310                 :         27 :                    httpread_length_get(c->hread));
     311                 :         27 :         return &c->body;
     312                 :            : }
     313                 :            : 
     314                 :            : 
     315                 :          9 : char * http_client_get_hdr_line(struct http_client *c, const char *tag)
     316                 :            : {
     317         [ -  + ]:          9 :         if (c->hread == NULL)
     318                 :          0 :                 return NULL;
     319                 :          9 :         return httpread_hdr_line_get(c->hread, tag);
     320                 :            : }
     321                 :            : 
     322                 :            : 
     323                 :         27 : char * http_link_update(char *url, const char *base)
     324                 :            : {
     325                 :            :         char *n;
     326                 :            :         size_t len;
     327                 :            :         const char *pos;
     328                 :            : 
     329                 :            :         /* RFC 2396, Chapter 5.2 */
     330                 :            :         /* TODO: consider adding all cases described in RFC 2396 */
     331                 :            : 
     332         [ -  + ]:         27 :         if (url == NULL)
     333                 :          0 :                 return NULL;
     334                 :            : 
     335         [ -  + ]:         27 :         if (os_strncmp(url, "http://", 7) == 0)
     336                 :          0 :                 return url; /* absolute link */
     337                 :            : 
     338         [ -  + ]:         27 :         if (os_strncmp(base, "http://", 7) != 0)
     339                 :          0 :                 return url; /* unable to handle base URL */
     340                 :            : 
     341                 :         27 :         len = os_strlen(url) + 1 + os_strlen(base) + 1;
     342                 :         27 :         n = os_malloc(len);
     343         [ -  + ]:         27 :         if (n == NULL)
     344                 :          0 :                 return url; /* failed */
     345                 :            : 
     346         [ -  + ]:         27 :         if (url[0] == '/') {
     347                 :          0 :                 pos = os_strchr(base + 7, '/');
     348         [ #  # ]:          0 :                 if (pos == NULL) {
     349                 :          0 :                         os_snprintf(n, len, "%s%s", base, url);
     350                 :            :                 } else {
     351                 :          0 :                         os_memcpy(n, base, pos - base);
     352                 :          0 :                         os_memcpy(n + (pos - base), url, os_strlen(url) + 1);
     353                 :            :                 }
     354                 :            :         } else {
     355                 :         27 :                 pos = os_strrchr(base + 7, '/');
     356         [ -  + ]:         27 :                 if (pos == NULL) {
     357                 :          0 :                         os_snprintf(n, len, "%s/%s", base, url);
     358                 :            :                 } else {
     359                 :         27 :                         os_memcpy(n, base, pos - base + 1);
     360                 :         27 :                         os_memcpy(n + (pos - base) + 1, url, os_strlen(url) +
     361                 :            :                                   1);
     362                 :            :                 }
     363                 :            :         }
     364                 :            : 
     365                 :         27 :         os_free(url);
     366                 :            : 
     367                 :         27 :         return n;
     368                 :            : }

Generated by: LCOV version 1.9