00001
00043 #include "includes.h"
00044
00045 #include "common.h"
00046 #include "eloop.h"
00047 #include "httpread.h"
00048
00049
00050
00051 #define HTTPREAD_READBUF_SIZE 1024
00052 #define HTTPREAD_HEADER_MAX_SIZE 4096
00053 #define HTTPREAD_BODYBUF_DELTA 4096
00054
00055 #if 0
00056
00057
00058
00059
00060 int httpread_debug = 99;
00061 #else
00062 #define httpread_debug 0
00063 #endif
00064
00065
00066
00067
00068 struct httpread {
00069
00070 int sd;
00071 void (*cb)(struct httpread *handle, void *cookie,
00072 enum httpread_event e);
00073 void *cookie;
00074 int max_bytes;
00075 int timeout_seconds;
00076
00077
00078 int sd_registered;
00079 int to_registered;
00080
00081 int got_hdr;
00082 char hdr[HTTPREAD_HEADER_MAX_SIZE+1];
00083 int hdr_nbytes;
00084
00085 enum httpread_hdr_type hdr_type;
00086 int version;
00087 int reply_code;
00088 int got_content_length;
00089 int content_length;
00090 int chunked;
00091 char *uri;
00092
00093 int got_body;
00094 char *body;
00095 int body_nbytes;
00096 int body_alloc_nbytes;
00097
00098 int got_file;
00099
00100
00101 int in_chunk_data;
00102 int chunk_start;
00103 int chunk_size;
00104 int in_trailer;
00105 enum trailer_state {
00106 trailer_line_begin = 0,
00107 trailer_empty_cr,
00108 trailer_nonempty,
00109 trailer_nonempty_cr,
00110 } trailer_state;
00111 };
00112
00113
00114
00115
00116
00117
00118 static int word_eq(char *s1, char *s2)
00119 {
00120 int c1;
00121 int c2;
00122 int end1 = 0;
00123 int end2 = 0;
00124 for (;;) {
00125 c1 = *s1++;
00126 c2 = *s2++;
00127 if (isalpha(c1) && isupper(c1))
00128 c1 = tolower(c1);
00129 if (isalpha(c2) && isupper(c2))
00130 c2 = tolower(c2);
00131 end1 = !isgraph(c1);
00132 end2 = !isgraph(c2);
00133 if (end1 || end2 || c1 != c2)
00134 break;
00135 }
00136 return end1 && end2;
00137 }
00138
00139
00140
00141
00142
00143 static int hex_value(int c)
00144 {
00145 if (isdigit(c))
00146 return c - '0';
00147 if (islower(c))
00148 return 10 + c - 'a';
00149 return 10 + c - 'A';
00150 }
00151
00152
00153 static void httpread_timeout_handler(void *eloop_data, void *user_ctx);
00154
00155
00156
00157
00158
00159
00160 void httpread_destroy(struct httpread *h)
00161 {
00162 if (httpread_debug >= 10)
00163 wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h);
00164 if (!h)
00165 return;
00166
00167 if (h->to_registered)
00168 eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
00169 h->to_registered = 0;
00170 if (h->sd_registered)
00171 eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
00172 h->sd_registered = 0;
00173 os_free(h->body);
00174 os_free(h->uri);
00175 os_memset(h, 0, sizeof(*h));
00176 h->sd = -1;
00177 os_free(h);
00178 }
00179
00180
00181
00182
00183 static void httpread_timeout_handler(void *eloop_data, void *user_ctx)
00184 {
00185 struct httpread *h = user_ctx;
00186 wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
00187 h->to_registered = 0;
00188 (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
00189 }
00190
00191
00192
00193
00194
00195 static int httpread_hdr_option_analyze(
00196 struct httpread *h,
00197 char *hbp
00198 )
00199 {
00200 if (word_eq(hbp, "CONTENT-LENGTH:")) {
00201 while (isgraph(*hbp))
00202 hbp++;
00203 while (*hbp == ' ' || *hbp == '\t')
00204 hbp++;
00205 if (!isdigit(*hbp))
00206 return -1;
00207 h->content_length = atol(hbp);
00208 h->got_content_length = 1;
00209 return 0;
00210 }
00211 if (word_eq(hbp, "TRANSFER_ENCODING:") ||
00212 word_eq(hbp, "TRANSFER-ENCODING:")) {
00213 while (isgraph(*hbp))
00214 hbp++;
00215 while (*hbp == ' ' || *hbp == '\t')
00216 hbp++;
00217
00218
00219
00220 if (word_eq(hbp, "CHUNKED")) {
00221 h->chunked = 1;
00222 h->in_chunk_data = 0;
00223
00224 }
00225 return 0;
00226 }
00227
00228 return 0;
00229 }
00230
00231
00232 static int httpread_hdr_analyze(struct httpread *h)
00233 {
00234 char *hbp = h->hdr;
00235 int standard_first_line = 1;
00236
00237
00238 h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN;
00239 if (!isgraph(*hbp))
00240 goto bad;
00241 if (os_strncmp(hbp, "HTTP/", 5) == 0) {
00242 h->hdr_type = HTTPREAD_HDR_TYPE_REPLY;
00243 standard_first_line = 0;
00244 hbp += 5;
00245 if (hbp[0] == '1' && hbp[1] == '.' &&
00246 isdigit(hbp[2]) && hbp[2] != '0')
00247 h->version = 1;
00248 while (isgraph(*hbp))
00249 hbp++;
00250 while (*hbp == ' ' || *hbp == '\t')
00251 hbp++;
00252 if (!isdigit(*hbp))
00253 goto bad;
00254 h->reply_code = atol(hbp);
00255 } else if (word_eq(hbp, "GET"))
00256 h->hdr_type = HTTPREAD_HDR_TYPE_GET;
00257 else if (word_eq(hbp, "HEAD"))
00258 h->hdr_type = HTTPREAD_HDR_TYPE_HEAD;
00259 else if (word_eq(hbp, "POST"))
00260 h->hdr_type = HTTPREAD_HDR_TYPE_POST;
00261 else if (word_eq(hbp, "PUT"))
00262 h->hdr_type = HTTPREAD_HDR_TYPE_PUT;
00263 else if (word_eq(hbp, "DELETE"))
00264 h->hdr_type = HTTPREAD_HDR_TYPE_DELETE;
00265 else if (word_eq(hbp, "TRACE"))
00266 h->hdr_type = HTTPREAD_HDR_TYPE_TRACE;
00267 else if (word_eq(hbp, "CONNECT"))
00268 h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT;
00269 else if (word_eq(hbp, "NOTIFY"))
00270 h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY;
00271 else if (word_eq(hbp, "M-SEARCH"))
00272 h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH;
00273 else if (word_eq(hbp, "M-POST"))
00274 h->hdr_type = HTTPREAD_HDR_TYPE_M_POST;
00275 else if (word_eq(hbp, "SUBSCRIBE"))
00276 h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE;
00277 else if (word_eq(hbp, "UNSUBSCRIBE"))
00278 h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE;
00279 else {
00280 }
00281
00282 if (standard_first_line) {
00283 char *rawuri;
00284 char *uri;
00285
00286 while (isgraph(*hbp))
00287 hbp++;
00288 while (*hbp == ' ' || *hbp == '\t')
00289 hbp++;
00290
00291
00292
00293
00294
00295 rawuri = hbp;
00296 while (isgraph(*hbp))
00297 hbp++;
00298 h->uri = os_malloc((hbp - rawuri) + 1);
00299 if (h->uri == NULL)
00300 goto bad;
00301 uri = h->uri;
00302 while (rawuri < hbp) {
00303 int c = *rawuri;
00304 if (c == '%' &&
00305 isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
00306 *uri++ = (hex_value(rawuri[1]) << 4) |
00307 hex_value(rawuri[2]);
00308 rawuri += 3;
00309 } else {
00310 *uri++ = c;
00311 rawuri++;
00312 }
00313 }
00314 *uri = 0;
00315 while (isgraph(*hbp))
00316 hbp++;
00317 while (*hbp == ' ' || *hbp == '\t')
00318 hbp++;
00319
00320 if (0 == strncmp(hbp, "HTTP/", 5)) {
00321 hbp += 5;
00322 if (hbp[0] == '1' && hbp[1] == '.' &&
00323 isdigit(hbp[2]) && hbp[2] != '0')
00324 h->version = 1;
00325 }
00326 }
00327
00328 while (*hbp)
00329 if (*hbp++ == '\n')
00330 break;
00331
00332
00333
00334
00335 for (;;) {
00336
00337 if (hbp[0] == '\n' ||
00338 (hbp[0] == '\r' && hbp[1] == '\n'))
00339 break;
00340 if (!isgraph(*hbp))
00341 goto bad;
00342 if (httpread_hdr_option_analyze(h, hbp))
00343 goto bad;
00344
00345 while (*hbp)
00346 if (*hbp++ == '\n')
00347 break;
00348 }
00349
00350
00351 if (h->chunked)
00352 h->got_content_length = 0;
00353
00354
00355
00356
00357
00358 switch (h->hdr_type) {
00359 case HTTPREAD_HDR_TYPE_REPLY:
00360
00361
00362
00363
00364 if (h->reply_code != 200)
00365 h->max_bytes = 0;
00366 break;
00367 case HTTPREAD_HDR_TYPE_GET:
00368 case HTTPREAD_HDR_TYPE_HEAD:
00369
00370
00371
00372 if (h->chunked == 0 && h->got_content_length == 0)
00373 h->max_bytes = 0;
00374 break;
00375 case HTTPREAD_HDR_TYPE_POST:
00376 case HTTPREAD_HDR_TYPE_PUT:
00377 case HTTPREAD_HDR_TYPE_DELETE:
00378 case HTTPREAD_HDR_TYPE_TRACE:
00379 case HTTPREAD_HDR_TYPE_CONNECT:
00380 case HTTPREAD_HDR_TYPE_NOTIFY:
00381 case HTTPREAD_HDR_TYPE_M_SEARCH:
00382 case HTTPREAD_HDR_TYPE_M_POST:
00383 case HTTPREAD_HDR_TYPE_SUBSCRIBE:
00384 case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
00385 default:
00386 break;
00387 }
00388
00389 return 0;
00390
00391 bad:
00392
00393 return -1;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403 static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
00404 {
00405 struct httpread *h = sock_ctx;
00406 int nread;
00407 char *rbp;
00408 char *hbp;
00409 char *bbp;
00410 char readbuf[HTTPREAD_READBUF_SIZE];
00411
00412 if (httpread_debug >= 20)
00413 wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h);
00414
00415
00416
00417
00418 nread = read(h->sd, readbuf, sizeof(readbuf));
00419 if (nread < 0)
00420 goto bad;
00421 if (nread == 0) {
00422
00423
00424
00425
00426 if (!h->got_hdr) {
00427
00428 wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h);
00429 goto bad;
00430 }
00431 if (h->chunked || h->got_content_length) {
00432
00433 wpa_printf(MSG_DEBUG,
00434 "httpread premature eof(%p) %d/%d",
00435 h, h->body_nbytes,
00436 h->content_length);
00437 goto bad;
00438 }
00439
00440
00441
00442
00443 if (httpread_debug >= 10)
00444 wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
00445 h->got_body = 1;
00446 goto got_file;
00447 }
00448 rbp = readbuf;
00449
00450
00451
00452
00453 if (!h->got_hdr) {
00454 hbp = h->hdr + h->hdr_nbytes;
00455
00456
00457
00458
00459
00460 for (;;) {
00461 if (nread == 0)
00462 goto get_more;
00463 if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {
00464 goto bad;
00465 }
00466 *hbp++ = *rbp++;
00467 nread--;
00468 h->hdr_nbytes++;
00469 if (h->hdr_nbytes >= 4 &&
00470 hbp[-1] == '\n' &&
00471 hbp[-2] == '\r' &&
00472 hbp[-3] == '\n' &&
00473 hbp[-4] == '\r' ) {
00474 h->got_hdr = 1;
00475 *hbp = 0;
00476 break;
00477 }
00478 }
00479
00480 if (httpread_hdr_analyze(h)) {
00481 wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h);
00482 goto bad;
00483 }
00484 if (h->max_bytes == 0) {
00485 if (httpread_debug >= 10)
00486 wpa_printf(MSG_DEBUG,
00487 "httpread no body hdr end(%p)", h);
00488 goto got_file;
00489 }
00490 if (h->got_content_length && h->content_length == 0) {
00491 if (httpread_debug >= 10)
00492 wpa_printf(MSG_DEBUG,
00493 "httpread zero content length(%p)",
00494 h);
00495 goto got_file;
00496 }
00497 }
00498
00499
00500
00501
00502 if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) ||
00503 !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) ||
00504 !os_strncasecmp(h->hdr, "HEAD", 4) ||
00505 !os_strncasecmp(h->hdr, "GET", 3)) {
00506 if (!h->got_body) {
00507 if (httpread_debug >= 10)
00508 wpa_printf(MSG_DEBUG,
00509 "httpread NO BODY for sp. type");
00510 }
00511 h->got_body = 1;
00512 goto got_file;
00513 }
00514
00515
00516
00517
00518
00519 if (nread == 0)
00520 goto get_more;
00521 if (!h->got_body) {
00522
00523
00524
00525
00526 if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) {
00527 char *new_body;
00528 int new_alloc_nbytes;
00529
00530 if (h->body_nbytes >= h->max_bytes)
00531 goto bad;
00532 new_alloc_nbytes = h->body_alloc_nbytes +
00533 HTTPREAD_BODYBUF_DELTA;
00534
00535
00536
00537
00538 if (h->got_content_length &&
00539 new_alloc_nbytes < (h->content_length + 1))
00540 new_alloc_nbytes = h->content_length + 1;
00541 if ((new_body = os_realloc(h->body, new_alloc_nbytes))
00542 == NULL)
00543 goto bad;
00544
00545 h->body = new_body;
00546 h->body_alloc_nbytes = new_alloc_nbytes;
00547 }
00548
00549 bbp = h->body + h->body_nbytes;
00550 for (;;) {
00551 int ncopy;
00552
00553 if (h->chunked && h->in_chunk_data == 0) {
00554
00555 char *cbp = h->body + h->chunk_start;
00556 if (bbp-cbp >= 2 && bbp[-2] == '\r' &&
00557 bbp[-1] == '\n') {
00558
00559
00560
00561
00562 if (!isxdigit(*cbp))
00563 goto bad;
00564 h->chunk_size = strtoul(cbp, NULL, 16);
00565
00566
00567
00568 h->body_nbytes = h->chunk_start;
00569 bbp = cbp;
00570 if (h->chunk_size == 0) {
00571
00572
00573 h->in_trailer = 1;
00574 if (httpread_debug >= 20)
00575 wpa_printf(
00576 MSG_DEBUG,
00577 "httpread end chunks(%p)", h);
00578 break;
00579 }
00580 h->in_chunk_data = 1;
00581
00582 }
00583 } else if (h->chunked) {
00584
00585 if ((h->body_nbytes - h->chunk_start) ==
00586 (h->chunk_size + 2)) {
00587
00588
00589
00590
00591
00592
00593 if (bbp[-1] == '\n' &&
00594 bbp[-2] == '\r') {
00595 } else
00596 goto bad;
00597 h->body_nbytes -= 2;
00598 bbp -= 2;
00599 h->chunk_start = h->body_nbytes;
00600 h->in_chunk_data = 0;
00601 h->chunk_size = 0;
00602 }
00603 } else if (h->got_content_length &&
00604 h->body_nbytes >= h->content_length) {
00605 h->got_body = 1;
00606 if (httpread_debug >= 10)
00607 wpa_printf(
00608 MSG_DEBUG,
00609 "httpread got content(%p)", h);
00610 goto got_file;
00611 }
00612 if (nread <= 0)
00613 break;
00614
00615 if (h->chunked && h->in_chunk_data) {
00616
00617
00618
00619 ncopy = (h->chunk_start + h->chunk_size + 2) -
00620 h->body_nbytes;
00621 } else if (h->chunked) {
00622
00623 *bbp++ = *rbp++;
00624 nread--;
00625 h->body_nbytes++;
00626 continue;
00627 } else if (h->got_content_length) {
00628 ncopy = h->content_length - h->body_nbytes;
00629 } else {
00630 ncopy = nread;
00631 }
00632
00633 if (ncopy > nread)
00634 ncopy = nread;
00635 os_memcpy(bbp, rbp, ncopy);
00636 bbp += ncopy;
00637 h->body_nbytes += ncopy;
00638 rbp += ncopy;
00639 nread -= ncopy;
00640 }
00641 }
00642 if (h->chunked && h->in_trailer) {
00643
00644
00645
00646
00647
00648
00649 bbp = h->body + h->body_nbytes;
00650 for (;;) {
00651 int c;
00652 if (nread <= 0)
00653 break;
00654 c = *rbp++;
00655 nread--;
00656 switch (h->trailer_state) {
00657 case trailer_line_begin:
00658 if (c == '\r')
00659 h->trailer_state = trailer_empty_cr;
00660 else
00661 h->trailer_state = trailer_nonempty;
00662 break;
00663 case trailer_empty_cr:
00664
00665 if (c == '\n') {
00666 h->trailer_state = trailer_line_begin;
00667 h->in_trailer = 0;
00668 if (httpread_debug >= 10)
00669 wpa_printf(
00670 MSG_DEBUG,
00671 "httpread got content(%p)", h);
00672 h->got_body = 1;
00673 goto got_file;
00674 }
00675 h->trailer_state = trailer_nonempty;
00676 break;
00677 case trailer_nonempty:
00678 if (c == '\r')
00679 h->trailer_state = trailer_nonempty_cr;
00680 break;
00681 case trailer_nonempty_cr:
00682 if (c == '\n')
00683 h->trailer_state = trailer_line_begin;
00684 else
00685 h->trailer_state = trailer_nonempty;
00686 break;
00687 }
00688 }
00689 }
00690 goto get_more;
00691
00692 bad:
00693
00694 wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h);
00695 (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR);
00696 return;
00697
00698 get_more:
00699 return;
00700
00701 got_file:
00702 if (httpread_debug >= 10)
00703 wpa_printf(MSG_DEBUG,
00704 "httpread got file %d bytes type %d",
00705 h->body_nbytes, h->hdr_type);
00706
00707 if (h->body)
00708 h->body[h->body_nbytes] = 0;
00709 h->got_file = 1;
00710
00711
00712
00713
00714 if (h->sd_registered)
00715 eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
00716 h->sd_registered = 0;
00717
00718
00719
00720 if (h->to_registered)
00721 eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
00722 h->to_registered = 0;
00723 (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
00724 }
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740 struct httpread * httpread_create(
00741 int sd,
00742 void (*cb)(struct httpread *handle, void *cookie,
00743 enum httpread_event e),
00744 void *cookie,
00745 int max_bytes,
00746 int timeout_seconds
00747 )
00748 {
00749 struct httpread *h = NULL;
00750
00751 h = os_zalloc(sizeof(*h));
00752 if (h == NULL)
00753 goto fail;
00754 h->sd = sd;
00755 h->cb = cb;
00756 h->cookie = cookie;
00757 h->max_bytes = max_bytes;
00758 h->timeout_seconds = timeout_seconds;
00759
00760 if (timeout_seconds > 0) {
00761 if (eloop_register_timeout(timeout_seconds, 0,
00762 httpread_timeout_handler,
00763 NULL, h)) {
00764
00765 goto fail;
00766 }
00767 h->to_registered = 1;
00768 }
00769 if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
00770 NULL, h)) {
00771
00772 goto fail;
00773 }
00774 h->sd_registered = 1;
00775 return h;
00776
00777 fail:
00778
00779
00780 httpread_destroy(h);
00781 return NULL;
00782 }
00783
00784
00785
00786 enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h)
00787 {
00788 return h->hdr_type;
00789 }
00790
00791
00792
00793
00794
00795 char * httpread_uri_get(struct httpread *h)
00796 {
00797 return h->uri;
00798 }
00799
00800
00801
00802 int httpread_reply_code_get(struct httpread *h)
00803 {
00804 return h->reply_code;
00805 }
00806
00807
00808
00809 int httpread_length_get(struct httpread *h)
00810 {
00811 return h->body_nbytes;
00812 }
00813
00814
00815
00816
00817
00818
00819 void * httpread_data_get(struct httpread *h)
00820 {
00821 return h->body ? h->body : "";
00822 }
00823
00824
00825
00826
00827
00828
00829 char * httpread_hdr_get(struct httpread *h)
00830 {
00831 return h->hdr;
00832 }
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843 char * httpread_hdr_line_get(struct httpread *h, const char *tag)
00844 {
00845 int tag_len = os_strlen(tag);
00846 char *hdr = h->hdr;
00847 hdr = os_strchr(hdr, '\n');
00848 if (hdr == NULL)
00849 return NULL;
00850 hdr++;
00851 for (;;) {
00852 if (!os_strncasecmp(hdr, tag, tag_len)) {
00853 hdr += tag_len;
00854 while (*hdr == ' ' || *hdr == '\t')
00855 hdr++;
00856 return hdr;
00857 }
00858 hdr = os_strchr(hdr, '\n');
00859 if (hdr == NULL)
00860 return NULL;
00861 hdr++;
00862 }
00863 }
00864