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