00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "klone_conf.h"
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <ctype.h>
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <u/libu.h>
00018 #include <klone/request.h>
00019 #include <klone/utils.h>
00020 #include <klone/io.h>
00021 #include <klone/ioprv.h>
00022 #include <klone/http.h>
00023 #include <klone/addr.h>
00024 #include <klone/vars.h>
00025 #include <klone/timer.h>
00026
00027 struct request_s
00028 {
00029 http_t *http;
00030 header_t *header;
00031 io_t *io;
00032 int method;
00033 char *cli_rq;
00034 char *uri;
00035 char *protocol;
00036 char *path_info;
00037 char *query;
00038 char *filename;
00039 char *resolved_path_info;
00040 char *resolved_filename;
00041 vars_t *args;
00042 vars_t *cookies;
00043 vars_t *uploads;
00044 char *content_type;
00045 char *content_encoding;
00046 size_t content_length;
00047 time_t if_modified_since;
00048 addr_t local_addr, peer_addr;
00049 int cgi;
00050 size_t idle_timeout;
00051 size_t post_timeout;
00052 size_t post_maxsize;
00053 };
00054
00055 typedef struct upload_info_s
00056 {
00057 char mime_type[MIME_TYPE_BUFSZ];
00058 char filename[U_FILENAME_MAX];
00059 size_t size;
00060 } upload_info_t;
00061
00062 enum {
00063 REQUEST_DEFAULT_IDLE_TIMEOUT = 10,
00064 REQUEST_DEFAULT_POST_TIMEOUT = 600,
00065 REQUEST_DEFAULT_POST_MAXSIZE = 5*1024000,
00066 };
00067
00068
00069 #define REQUEST_SET_STRING_FIELD(lval, rval) \
00070 do { \
00071 U_FREE(lval); \
00072 if(rval) \
00073 { \
00074 lval = u_strdup(rval); \
00075 dbg_err_if(lval == NULL); \
00076 } \
00077 } while(0)
00078
00092 int request_is_encoding_accepted(request_t *rq, const char *encoding)
00093 {
00094 char *pp, *tok, *src, *buf = NULL;
00095 const char *accept_encoding;
00096 int rc = 0;
00097
00098 dbg_err_if (rq == NULL);
00099 dbg_err_if (encoding == NULL);
00100
00101 accept_encoding = header_get_field_value(rq->header, "Accept-Encoding");
00102 if(accept_encoding)
00103 {
00104
00105 buf = u_strdup(accept_encoding);
00106 dbg_err_if(buf == NULL);
00107
00108
00109 for(src = buf; (tok = strtok_r(src, " ,", &pp)) != NULL; src = NULL)
00110 {
00111 if(strcasecmp(tok, encoding) == 0)
00112 {
00113 rc++;
00114 break;
00115 }
00116 }
00117
00118 U_FREE(buf);
00119 }
00120
00121 return rc;
00122 err:
00123 U_FREE(buf);
00124 return 0;
00125 }
00126
00141 io_t *request_io(request_t *rq)
00142 {
00143 dbg_return_if (rq == NULL, NULL);
00144
00145 return rq->io;
00146 }
00147
00158 vars_t *request_get_cookies(request_t *rq)
00159 {
00160 dbg_return_if (rq == NULL, NULL);
00161
00162 return rq->cookies;
00163 }
00164
00175 const char *request_get_cookie(request_t *rq, const char *name)
00176 {
00177 var_t *v;
00178
00179 dbg_return_if (rq == NULL, NULL);
00180 dbg_return_if (name == NULL, NULL);
00181
00182 v = vars_get(rq->cookies, name);
00183
00184 return v ? var_get_value(v): NULL;
00185 }
00186
00196 vars_t *request_get_args(request_t *rq)
00197 {
00198 dbg_return_if (rq == NULL, NULL);
00199
00200 return rq->args;
00201 }
00202
00215 const char *request_get_arg(request_t *rq, const char *name)
00216 {
00217 var_t *v;
00218
00219 dbg_return_if (rq == NULL, NULL);
00220 dbg_return_if (name == NULL, NULL);
00221
00222 v = vars_get(rq->args, name);
00223
00224 return v ? var_get_value(v): NULL;
00225 }
00226
00236 const char *request_get_uri(request_t *rq)
00237 {
00238 dbg_return_if (rq == NULL, NULL);
00239
00240 return rq->uri;
00241 }
00242
00252 const char *request_get_filename(request_t *rq)
00253 {
00254 dbg_return_if (rq == NULL, NULL);
00255
00256 return rq->filename;
00257 }
00258
00268 const char *request_get_query_string(request_t *rq)
00269 {
00270 dbg_return_if (rq == NULL, NULL);
00271
00272 return rq->query;
00273 }
00274
00284 const char *request_get_path_info(request_t *rq)
00285 {
00286 dbg_return_if (rq == NULL, NULL);
00287
00288 return rq->path_info;
00289 }
00290
00291
00292 static int request_parse_ims(request_t *rq)
00293 {
00294 const char *ims;
00295
00296 dbg_err_if (rq == NULL);
00297
00298 rq->if_modified_since = 0;
00299
00300 ims = header_get_field_value(rq->header, "If-Modified-Since");
00301 if(ims)
00302 dbg_err_if(u_httpdate_to_tt(ims, &rq->if_modified_since));
00303
00304 err:
00305 return 0;
00306 }
00307
00317 time_t request_get_if_modified_since(request_t *rq)
00318 {
00319 dbg_return_if (rq == NULL, (time_t) -1);
00320
00321 return rq->if_modified_since;
00322 }
00323
00324
00334 http_t* request_get_http(request_t *rq)
00335 {
00336 dbg_return_if (rq == NULL, NULL);
00337
00338 return rq->http;
00339 }
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 int request_bind(request_t *rq, io_t *in)
00352 {
00353 dbg_return_if (rq == NULL, ~0);
00354 dbg_return_if (in == NULL, ~0);
00355
00356 rq->io = in;
00357
00358 return 0;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 void request_clear_uri(request_t *rq)
00371 {
00372 U_FREE(rq->uri);
00373 U_FREE(rq->protocol);
00374 U_FREE(rq->path_info);
00375 U_FREE(rq->query);
00376 U_FREE(rq->filename);
00377 U_FREE(rq->resolved_path_info);
00378 U_FREE(rq->resolved_filename);
00379 U_FREE(rq->content_type);
00380 U_FREE(rq->content_encoding);
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 int request_set_uri(request_t *rq, const char *uri,
00397 int (*is_valid_uri)(void*, const char *, size_t),
00398 void* arg)
00399 {
00400 enum { REQUEST_URI_MAX_LENGTH = 4095 };
00401 char *p, *fn, *pi, *cp = NULL;
00402 size_t uri_len = strlen(uri);
00403
00404 dbg_err_if (rq == NULL);
00405 dbg_err_if (uri == NULL);
00406
00407
00408
00409 request_clear_uri(rq);
00410
00411
00412
00413 warn_err_ifm(uri_len > REQUEST_URI_MAX_LENGTH, "Request URI too long");
00414
00415 REQUEST_SET_STRING_FIELD(rq->uri, uri);
00416
00417
00418 if((p = strchr(uri, '?')) != NULL)
00419 dbg_err_if(request_set_query_string(rq, ++p));
00420
00421 cp = (char*)u_malloc(uri_len + 1);
00422 dbg_err_if(cp == NULL);
00423
00424
00425 dbg_err_if(u_urlncpy(cp, rq->uri, uri_len, URLCPY_DECODE) <= 0);
00426
00427 if((p = strchr(cp, '?')) != NULL)
00428 *p++ = 0;
00429
00430
00431 dbg_err_if(u_path_normalize(cp));
00432
00433
00434 dbg_err_if(request_set_filename(rq, cp));
00435
00436
00437 fn = cp;
00438 pi = fn + strlen(fn);
00439 for(;;)
00440 {
00441 if(is_valid_uri == NULL || is_valid_uri(arg, fn, pi - fn))
00442 {
00443 dbg_err_if(request_set_filename(rq, fn));
00444 rq->filename[pi-fn] = 0;
00445 if(strlen(pi))
00446 dbg_err_if(request_set_path_info(rq, pi));
00447 break;
00448 } else {
00449 if((p = u_strnrchr(fn, '/', pi - fn)) == NULL)
00450 break;
00451 pi = p;
00452 }
00453 }
00454
00455 U_FREE(cp);
00456
00457 return 0;
00458 err:
00459 U_FREE(cp);
00460 return ~0;
00461 }
00462
00463 static int request_set_proto(request_t *rq, const char *proto)
00464 {
00465 dbg_err_if (rq == NULL);
00466 dbg_err_if (proto == NULL);
00467
00468
00469 if(strncasecmp(proto, "http", 4))
00470 return ~0;
00471
00472 REQUEST_SET_STRING_FIELD(rq->protocol, proto);
00473
00474 return 0;
00475 err:
00476 return ~0;
00477 }
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 int request_set_client_request(request_t *rq, const char *ln)
00490 {
00491 char *p;
00492 dbg_err_if(rq == NULL);
00493 dbg_err_if(ln == NULL);
00494
00495 rq->cli_rq = u_strdup(ln);
00496 dbg_err_if(rq->cli_rq == NULL);
00497
00498
00499 for(p = rq->cli_rq; *p && (*p != '\r' && *p != '\n'); ++p)
00500 continue;
00501 *p = 0;
00502
00503 return 0;
00504 err:
00505 return ~0;
00506 }
00507
00517 const char *request_get_client_request(request_t *rq)
00518 {
00519 return rq->cli_rq;
00520 }
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 int request_set_method(request_t *rq, const char *method)
00531 {
00532 dbg_return_if (rq == NULL, ~0);
00533 dbg_return_if (method == NULL, ~0);
00534
00535 if(!strcasecmp(method, "get"))
00536 rq->method = HM_GET;
00537 else if(!strcasecmp(method, "head"))
00538 rq->method = HM_HEAD;
00539 else if(!strcasecmp(method, "post"))
00540 rq->method = HM_POST;
00541 else {
00542
00543 rq->method = HM_UNKNOWN;
00544 return ~0;
00545 }
00546
00547 return 0;
00548 }
00549
00550 static int request_set_content_length(request_t *rq)
00551 {
00552 const char *clen;
00553 size_t len;
00554
00555 dbg_err_if (rq == NULL);
00556
00557 clen = header_get_field_value(rq->header, "Content-Length");
00558 dbg_err_if(clen == NULL || (len = atoi(clen)) < 0);
00559
00560 rq->content_length = len;
00561
00562 return 0;
00563 err:
00564 return ~0;
00565 }
00566
00567 static int request_parse_cookie(request_t *rq, field_t *field)
00568 {
00569 enum { BUFSZ = 4096 };
00570 char *pp, *tok, *src, buf[BUFSZ];
00571
00572 dbg_err_if (rq == NULL);
00573 dbg_err_if (field == NULL);
00574
00575 dbg_err_if(field_get_value(field) == NULL);
00576
00577
00578 strncpy(buf, field_get_value(field), BUFSZ);
00579
00580
00581 for(src = buf; (tok = strtok_r(src, " ;", &pp)) != NULL; src = NULL)
00582 dbg_if(vars_add_urlvar(rq->cookies, tok, NULL));
00583
00584 return 0;
00585 err:
00586 return ~0;
00587 }
00588
00589 static int request_parse_cookies(request_t *rq)
00590 {
00591 field_t *f;
00592 size_t i, count;
00593
00594 dbg_err_if (rq == NULL);
00595
00596 count = header_field_count(rq->header);
00597 for(i = 0; i < count; ++i)
00598 {
00599 f = header_get_fieldn(rq->header, i);
00600 dbg_err_if(f == NULL);
00601 if(strcasecmp(field_get_name(f), "cookie") == 0)
00602 dbg_err_if(request_parse_cookie(rq, f));
00603 }
00604
00605 return 0;
00606 err:
00607 return ~0;
00608 }
00609
00610 static int request_parse_query_args(request_t *rq)
00611 {
00612 char *pp, *tok, *src, *query = NULL;
00613
00614 dbg_err_if (rq == NULL);
00615
00616 if(!rq->query)
00617 return 0;
00618
00619
00620 query = u_strdup(rq->query);
00621 dbg_err_if(query == NULL);
00622
00623
00624 for(src = query; (tok = strtok_r(src, "&", &pp)) != NULL; src = NULL)
00625 {
00626
00627 dbg_if(vars_add_urlvar(rq->args, tok, NULL));
00628 }
00629
00630 U_FREE(query);
00631
00632 return 0;
00633 err:
00634 U_FREE(query);
00635 return ~0;
00636 }
00637
00638
00639 void request_set_cgi(request_t *rq, int cgi)
00640 {
00641 rq->cgi = cgi;
00642 return;
00643 }
00644
00655 ssize_t request_get_content_length(request_t *rq)
00656 {
00657 dbg_return_if (rq == NULL, -1);
00658
00659 return (ssize_t) rq->content_length;
00660 }
00661
00662 static int match_content_type(header_t *h, const char *mime_type)
00663 {
00664 const char *ct;
00665
00666 dbg_return_if (h == NULL, 0);
00667 dbg_return_if (mime_type == NULL, 0);
00668
00669 ct = header_get_field_value(h, "Content-Type");
00670 if(ct == NULL || strncasecmp(ct, mime_type, strlen(mime_type)))
00671 return 0;
00672
00673 return 1;
00674 }
00675
00676 static int request_is_multipart_formdata(request_t *rq)
00677 {
00678 return match_content_type(rq->header, "multipart/form-data");
00679 }
00680
00681 static int request_parse_urlencoded_data(request_t *rq)
00682 {
00683 ssize_t qsz, len;
00684
00685 dbg_err_if (rq == NULL);
00686
00687 len = rq->content_length;
00688
00689 qsz = (rq->query ? strlen(rq->query) : 0);
00690
00691
00692 rq->query = u_realloc(rq->query, len + qsz + 2);
00693 dbg_err_if(rq->query == NULL);
00694
00695
00696
00697 rq->query[qsz] = 0;
00698 if(qsz)
00699 {
00700 strcat(rq->query, "&");
00701 ++qsz;
00702 }
00703
00704
00705 dbg_err_if(io_read(rq->io, rq->query + qsz, len) != len);
00706
00707
00708 rq->query[qsz + len] = 0;
00709
00710
00711 dbg_err_if(request_parse_query_args(rq));
00712
00713 return 0;
00714 err:
00715 return ~0;
00716 }
00717
00718
00719
00720 static int request_get_fieldparam(request_t *rq, const char *field_name,
00721 const char *param_name, char *buf, size_t size)
00722 {
00723 const char *param_value, *field_value, *p;
00724 size_t pv_len;
00725
00726 dbg_err_if (rq == NULL);
00727 dbg_err_if (field_name == NULL);
00728 dbg_err_if (param_name == NULL);
00729 dbg_err_if (buf == NULL);
00730 dbg_err_if (size == 0);
00731
00732 field_value = header_get_field_value(rq->header, field_name);
00733 dbg_err_if(field_value == NULL);
00734
00735
00736 param_value = u_stristr(field_value, param_name);
00737 dbg_err_if(param_value == NULL);
00738
00739
00740 param_value += strlen(param_name);
00741
00742
00743 dbg_err_if(*param_value++ != '=');
00744
00745
00746 for(p = param_value; ;++p)
00747 if(*p == '\0' || *p == ';' || isspace(*p))
00748 break;
00749
00750
00751 pv_len = p - param_value;
00752
00753
00754 dbg_err_if(pv_len > size - 1);
00755
00756
00757 strncpy(buf, param_value, pv_len);
00758 buf[MIN(pv_len, size - 1)] = 0;
00759
00760 return 0;
00761 err:
00762 return ~0;
00763 }
00764
00765 static int is_multipart_mixed(header_t *h)
00766 {
00767 return match_content_type(h, "multipart/mixed");
00768 }
00769
00770 static int is_encoded(header_t *h)
00771 {
00772 const char *cte;
00773
00774 dbg_return_if (h == NULL, 0);
00775
00776 if((cte = header_get_field_value(h, "Content-Transfer-Encoding")) == NULL)
00777 return 0;
00778
00779 if(strcasecmp(cte, "binary") == 0)
00780 return 0;
00781
00782 return 1;
00783 }
00784
00785 static inline int is_nl(char c)
00786 {
00787 return (c == '\n' || c == '\r' ? c : 0);
00788 }
00789
00790 static inline int is_quote(char c)
00791 {
00792 return (c == '"' || c == '\'' ? c : 0);
00793 }
00794
00795 static int parse_content_disposition(header_t *h, char *name, char *filename,
00796 size_t prmsz)
00797 {
00798 enum { BUFSZ = 512 };
00799 char *pp, *tok, *src, buf[BUFSZ];
00800 size_t n_len, fn_len;
00801 const char *cd;
00802 int q;
00803
00804 dbg_err_if (h == NULL);
00805 dbg_err_if (name == NULL);
00806 dbg_err_if (filename == NULL);
00807 dbg_err_if (prmsz == 0);
00808
00809 cd = header_get_field_value(h, "Content-Disposition");
00810 dbg_err_if(cd == NULL);
00811
00812 dbg_err_if(strlen(cd) >= BUFSZ);
00813
00814
00815 dbg_err_if(strncmp(cd, "form-data", strlen("form-data")));
00816
00817 name[0] = filename[0] = 0;
00818
00819
00820 strncpy(buf, cd, BUFSZ);
00821
00822
00823 n_len = strlen("name=");
00824 fn_len = strlen("filename=");
00825
00826
00827 for(src = buf; (tok = strtok_r(src, " ;", &pp)) != NULL; src = NULL)
00828 {
00829 if(strncmp(tok, "form-data", strlen("form-data")) == 0)
00830 continue;
00831 else if(strncmp(tok, "name=", n_len) == 0) {
00832
00833 tok += n_len;
00834
00835
00836 if((q = is_quote(tok[0])) != 0)
00837 ++tok;
00838 if(strlen(tok) && tok[strlen(tok) - 1] == q)
00839 tok[strlen(tok) - 1] = 0;
00840
00841 strncpy(name, tok, prmsz);
00842 } else if(strncmp(tok, "filename=", fn_len) == 0) {
00843
00844 tok += fn_len;
00845
00846
00847 if((q = is_quote(tok[0])) != 0)
00848 ++tok;
00849 if(strlen(tok) && tok[strlen(tok) - 1] == q)
00850 tok[strlen(tok) - 1] = 0;
00851
00852 strncpy(filename, tok, prmsz);
00853 }
00854
00855 }
00856
00857 return 0;
00858 err:
00859 return ~0;
00860 }
00861
00862
00863
00864
00865
00866
00867
00868
00869 static ssize_t read_until(io_t *io, const char *stop_at, char *obuf,
00870 size_t size, int *found)
00871 {
00872
00873
00874
00875 #define SETUP_BUF_ACCESS_AT(idx) \
00876 if(idx >= wtot) { \
00877 if(idx >= size) \
00878 return wtot; \
00879 \
00880 \
00881 dbg_err_if((rc = io_read(io, wbuf, idx + 1 - wtot)) < 0); \
00882 if(rc == 0 || rc < idx + 1 - wtot) \
00883 return wtot + rc; \
00884 wbuf += rc; \
00885 wtot += rc; \
00886 }
00887
00888 int sa_len = strlen(stop_at);
00889 int i, t, shift[256], rc;
00890 unsigned char c;
00891 size_t wtot = 0;
00892 char *wbuf = obuf;
00893
00894 dbg_err_if (io == NULL);
00895 dbg_err_if (stop_at == NULL);
00896 dbg_err_if (obuf == NULL);
00897
00898 dbg_err_if (found == NULL);
00899
00900 for(i = 0; i < 256; ++i)
00901 shift[i] = sa_len;
00902
00903 for(i = 0; i < sa_len; ++i)
00904 shift[ stop_at[i] ] = sa_len - i - 1;
00905
00906 *found = 0;
00907
00908 for(i = t = sa_len-1; t >= 0; --i, --t)
00909 {
00910 SETUP_BUF_ACCESS_AT(i);
00911
00912 while((c = obuf[i]) != stop_at[t])
00913 {
00914 i += MAX(sa_len - t, shift[c]);
00915
00916 SETUP_BUF_ACCESS_AT(i);
00917
00918 t = sa_len - 1;
00919 }
00920 }
00921
00922 *found = 1;
00923
00924
00925 return wtot;
00926 err:
00927 return -1;
00928 }
00929
00930
00948 vars_t *request_get_uploads(request_t *rq)
00949 {
00950 return rq->uploads;
00951 }
00952
00953
00954
00955
00956
00957
00958
00959
00960 static int request_add_uploaded_file(request_t *rq, const char *name,
00961 const char *filename, const char *tmp_filename, const char *mime_type)
00962 {
00963 struct stat st;
00964 var_t *v = NULL;
00965 upload_info_t *info = NULL;
00966
00967 dbg_err_if (rq == NULL);
00968 dbg_err_if (name == NULL);
00969
00970 dbg_err_if (tmp_filename == NULL);
00971
00972
00973 dbg_err_sif (stat(tmp_filename, &st) < 0);
00974
00975
00976 dbg_err_if(var_create(name, tmp_filename, &v));
00977
00978
00979 dbg_err_if((info = u_zalloc(sizeof(upload_info_t))) == NULL);
00980
00981
00982 info->size = st.st_size;
00983 if(mime_type)
00984 snprintf(info->mime_type, MIME_TYPE_BUFSZ, "%s", mime_type);
00985 else
00986 info->mime_type[0] = 0;
00987
00988 if(filename)
00989 snprintf(info->filename, U_FILENAME_MAX, "%s", filename);
00990
00991
00992 var_set_opaque(v, info);
00993 info = NULL;
00994
00995
00996 dbg_err_if(vars_add(rq->uploads, v));
00997
00998 return 0;
00999 err:
01000 if(info)
01001 U_FREE(info);
01002 if(v)
01003 var_free(v);
01004 return ~0;
01005 }
01006
01007 static int request_get_uploaded_filev(request_t *rq, var_t *v,
01008 char local_filename[U_FILENAME_MAX], char client_filename[U_FILENAME_MAX],
01009 char mime_type[MIME_TYPE_BUFSZ], size_t *file_size)
01010 {
01011 upload_info_t *info;
01012 const char *tmp_fqn;
01013
01014 dbg_err_if (rq == NULL);
01015 dbg_err_if (v == NULL);
01016 dbg_err_if (local_filename == NULL);
01017 dbg_err_if (client_filename == NULL);
01018 dbg_err_if (mime_type == NULL);
01019 dbg_err_if (file_size == NULL);
01020
01021 info = var_get_opaque(v);
01022 dbg_err_if(info == NULL);
01023
01024 tmp_fqn = var_get_value(v);
01025 dbg_err_if(tmp_fqn == NULL);
01026
01027
01028 strncpy(local_filename, tmp_fqn, U_FILENAME_MAX);
01029 strncpy(mime_type, info->mime_type, MIME_TYPE_BUFSZ);
01030 strncpy(client_filename, info->filename, U_FILENAME_MAX);
01031 *file_size = info->size;
01032
01033 return 0;
01034 err:
01035 return ~0;
01036 }
01037
01059 int request_get_uploaded_file(request_t *rq, const char *name, size_t idx,
01060 char local_filename[U_FILENAME_MAX], char client_filename[U_FILENAME_MAX],
01061 char mime_type[MIME_TYPE_BUFSZ], size_t *file_size)
01062 {
01063 var_t *v;
01064 upload_info_t *info;
01065 const char *tmp_fqn;
01066
01067 dbg_err_if (rq == NULL);
01068 dbg_err_if (name == NULL);
01069 dbg_err_if (idx >= vars_count(rq->uploads));
01070 dbg_err_if (local_filename == NULL);
01071 dbg_err_if (client_filename == NULL);
01072 dbg_err_if (mime_type == NULL);
01073 dbg_err_if (file_size == NULL);
01074
01075 v = vars_geti(rq->uploads, name, idx);
01076 dbg_err_if(v == NULL);
01077
01078 return request_get_uploaded_filev(rq, v, local_filename, client_filename,
01079 mime_type, file_size);
01080 err:
01081 return ~0;
01082 }
01083
01084 static int request_parse_multipart_chunk(request_t *rq, io_t *io,
01085 const char *boundary, int *eof)
01086 {
01087 enum { PRMSZ = 512, BUFSZ = 4096 };
01088 header_t *h = NULL;
01089 io_t *tmpio = NULL;
01090 var_t *v = NULL;
01091 char name[PRMSZ], filename[PRMSZ], buf[BUFSZ];
01092 size_t bound_len, len;
01093 int found;
01094 ssize_t rc;
01095
01096
01097 dbg_err_if(header_create(&h));
01098
01099
01100 dbg_err_if(header_load(h, io));
01101
01102 warn_err_ifm(is_multipart_mixed(h),
01103 "multipart/mixed content is not supported yet");
01104
01105
01106 warn_err_ifm(is_encoded(h),
01107 "encoded file upload is not supported");
01108
01109 dbg_err_if(parse_content_disposition(h, name, filename, PRMSZ));
01110
01111
01112 bound_len = strlen(boundary);
01113
01114 if(filename[0] != '\0')
01115 {
01116 dbg_err_if(BUFSZ <= bound_len);
01117
01118
01119 dbg_err_if(u_tmpfile_open(&tmpio));
01120
01121 for(found = 0; !found; )
01122 {
01123 rc = read_until(io, boundary, buf, BUFSZ, &found);
01124 dbg_err_if(rc <= 0);
01125
01126
01127 if(found)
01128 {
01129 rc -= (bound_len + 2);
01130 dbg_err_if(rc < 0);
01131 }
01132
01133
01134 dbg_err_if(io_write(tmpio, buf, rc) < 0);
01135 }
01136
01137
01138 dbg_err_if(io_name_get(tmpio, buf, BUFSZ));
01139
01140
01141 io_free(tmpio); tmpio = NULL;
01142
01143
01144 dbg_err_if(request_add_uploaded_file(rq, name, filename, buf,
01145 header_get_field_value(h, "Content-Type")));
01146
01147
01148 dbg_err_if(io_gets(io, buf, BUFSZ) <= 0);
01149
01150 if(strncmp(buf, "--", 2) == 0)
01151 *eof = 1;
01152
01153 } else {
01154
01155 rc = read_until(io, boundary, buf, BUFSZ, &found);
01156 dbg_err_if(rc <= 0);
01157
01158
01159 warn_err_ifm(!found, "malformed request or BUFSZ too small");
01160
01161 rc -= (bound_len + 2);
01162 dbg_err_if(rc < 0);
01163
01164
01165 buf[rc] = 0;
01166
01167
01168 dbg_err_if(var_bin_create(name, buf, rc, &v));
01169 dbg_if(vars_add(rq->args, v));
01170
01171
01172 dbg_err_if(io_gets(io, buf, BUFSZ) <= 0);
01173
01174 if(strncmp(buf, "--", 2) == 0)
01175 *eof = 1;
01176 }
01177
01178 header_free(h);
01179
01180 return 0;
01181 err:
01182 if(tmpio)
01183 io_free(tmpio);
01184 if(h)
01185 header_free(h);
01186 return ~0;
01187 }
01188
01189 static int request_parse_multipart_data(request_t *rq)
01190 {
01191 enum { BOUNDARY_BUFSZ = 128, BUFSZ = 1024 };
01192 char boundary[BOUNDARY_BUFSZ], buf[BUFSZ];
01193 int eof;
01194
01195
01196 strcpy(boundary, "--");
01197
01198 dbg_err_if(request_get_fieldparam(rq, "Content-Type", "boundary",
01199 boundary + 2, BOUNDARY_BUFSZ - 2));
01200
01201 dbg_err_if(strlen(boundary) == 0);
01202
01203
01204 for(;;)
01205 {
01206 dbg_err_if(io_gets(rq->io, buf, BUFSZ) <= 0);
01207 if(!strncmp(buf, boundary, strlen(boundary)))
01208 break;
01209 }
01210
01211
01212 for(eof = 0; eof == 0; )
01213 dbg_err_if(request_parse_multipart_chunk(rq, rq->io, boundary, &eof));
01214
01215 return 0;
01216 err:
01217 return ~0;
01218 }
01219
01220 static int request_cb_close_socket(talarm_t *al, void *arg)
01221 {
01222 io_t *io = (io_t*)arg;
01223
01224 u_unused_args(al);
01225
01226 warn("[%x] connection timed out, closing", io);
01227
01228
01229 io_close(io);
01230
01231 return 0;
01232 }
01233
01234 int request_parse_data(request_t *rq)
01235 {
01236 talarm_t *al = NULL;
01237 int rc = HTTP_STATUS_BAD_REQUEST;
01238
01239 if(rq->method == HM_POST)
01240 {
01241
01242 dbg_err_if(timerm_add(rq->post_timeout, request_cb_close_socket,
01243 (void*)rq->io, &al));
01244
01245
01246 dbg_err_if(request_set_content_length(rq) &&
01247 (rc = HTTP_STATUS_LENGTH_REQUIRED));
01248
01249 if(rq->content_length == 0)
01250 return 0;
01251
01252
01253 dbg_err_if(rq->content_length > rq->post_maxsize &&
01254 (rc = HTTP_STATUS_REQUEST_TOO_LARGE));
01255
01256 if(request_is_multipart_formdata(rq))
01257 {
01258
01259 dbg_err_if(request_parse_query_args(rq));
01260
01261
01262 dbg_err_if(request_parse_multipart_data(rq));
01263 } else {
01264
01265 dbg_err_if(request_parse_urlencoded_data(rq));
01266 }
01267
01268
01269 dbg_if(timerm_del(al)); al = NULL;
01270 } else {
01271
01272 dbg_err_if(request_parse_query_args(rq));
01273 }
01274
01275 return 0;
01276 err:
01277 return rc;
01278 }
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289 int request_parse_header(request_t *rq,
01290 int (*is_valid_uri)(void*, const char *, size_t),
01291 void* arg)
01292 {
01293 enum { BUFSZ = 4096 };
01294 const char WP[] = " \t\r\n";
01295 char ln[BUFSZ], *pp, *method, *uri, *proto;
01296 talarm_t *al = NULL;
01297 int rc = HTTP_STATUS_BAD_REQUEST;
01298
01299 dbg_err_if (rq == NULL);
01300 dbg_err_if (rq->io == NULL);
01301
01302
01303 dbg_err_if(timerm_add(rq->idle_timeout, request_cb_close_socket,
01304 (void*)rq->io, &al));
01305
01306 if(!rq->cgi)
01307 {
01308
01309 dbg_err_if(io_gets(rq->io, ln, BUFSZ) <= 0);
01310
01311
01312 dbg_err_if(request_set_client_request(rq, ln));
01313
01314 method = strtok_r(ln, WP, &pp);
01315 dbg_err_if(!method || request_set_method(rq, method));
01316
01317 uri = strtok_r(NULL, WP, &pp);
01318 dbg_err_if(!uri || request_set_uri(rq, uri, is_valid_uri, arg));
01319
01320
01321 proto = strtok_r(NULL, WP, &pp);
01322 dbg_err_if(!proto || request_set_proto(rq, proto));
01323
01324 dbg_err_if(header_load(rq->header, rq->io));
01325 } else
01326 dbg_err_if(header_load_from_cgienv(rq->header));
01327
01328
01329 dbg_err_if(request_parse_ims(rq));
01330
01331
01332 dbg_err_if(request_parse_cookies(rq));
01333
01334
01335 if(request_get_method(rq) == HM_POST)
01336 dbg_err_if(request_set_content_length(rq));
01337
01338
01339 dbg_if(timerm_del(al)); al = NULL;
01340
01341
01342
01343
01344 return 0;
01345 err:
01346 if(al)
01347 timerm_del(al);
01348 return rc;
01349 }
01350
01361 int request_get_method(request_t *rq)
01362 {
01363 dbg_return_if (rq == NULL, HM_UNKNOWN);
01364
01365 return rq->method;
01366 }
01367
01378 const char* request_get_protocol(request_t *rq)
01379 {
01380 dbg_return_if (rq == NULL, "unknown");
01381
01382 return rq->protocol;
01383 }
01384
01394 const char *request_get_resolved_filename(request_t *rq)
01395 {
01396 dbg_return_if (rq == NULL, NULL);
01397
01398 return rq->resolved_filename;
01399 }
01400
01410 const char *request_get_resolved_path_info(request_t *rq)
01411 {
01412 dbg_return_if (rq == NULL, NULL);
01413
01414 return rq->resolved_path_info;
01415 }
01416
01417 int request_print(request_t *rq)
01418 {
01419 dbg_return_if (rq == NULL, ~0);
01420
01421 dbg("method: %u", rq->method);
01422 dbg("uri: %s", rq->uri);
01423 dbg("proto: %s", rq->protocol);
01424 dbg("filename: %s", rq->filename);
01425 dbg("resolved filename: %s", rq->resolved_filename);
01426 dbg("path_info: %s", rq->path_info);
01427 dbg("resolved path_info: %s", rq->resolved_path_info);
01428 dbg("query: %s", rq->query);
01429
01430 return 0;
01431 }
01432
01433 static int request_load_config(request_t *rq)
01434 {
01435 u_config_t *c;
01436 const char *v;
01437
01438 dbg_err_if (rq == NULL);
01439 dbg_err_if (rq->http == NULL);
01440 dbg_err_if (http_get_config(rq->http) == NULL);
01441
01442 c = http_get_config(rq->http);
01443
01444
01445 rq->idle_timeout = REQUEST_DEFAULT_IDLE_TIMEOUT;
01446 rq->post_timeout = REQUEST_DEFAULT_POST_TIMEOUT;
01447 rq->post_maxsize = REQUEST_DEFAULT_POST_MAXSIZE;
01448
01449
01450 if((v = u_config_get_subkey_value(c, "idle_timeout")) != NULL)
01451 rq->idle_timeout = MAX(1, atoi(v));
01452
01453
01454 if((v = u_config_get_subkey_value(c, "post_timeout")) != NULL)
01455 rq->post_timeout = MAX(5, atoi(v));
01456
01457
01458 if((v = u_config_get_subkey_value(c, "post_maxsize")) != NULL)
01459 rq->post_maxsize = MAX(1024, atoi(v));
01460
01461 return 0;
01462 err:
01463 return ~0;
01464 }
01465
01466 int request_create(http_t *http, request_t **prq)
01467 {
01468 request_t *rq = NULL;
01469
01470 dbg_return_if (prq == NULL, ~0);
01471 dbg_return_if (http == NULL, ~0);
01472
01473 rq = u_zalloc(sizeof(request_t));
01474 dbg_err_if(rq == NULL);
01475
01476 dbg_err_if(header_create(&rq->header));
01477
01478 dbg_err_if(vars_create(&rq->args));
01479 dbg_err_if(vars_create(&rq->cookies));
01480 dbg_err_if(vars_create(&rq->uploads));
01481
01482 rq->http = http;
01483
01484 dbg_err_if(request_load_config(rq));
01485
01486 *prq = rq;
01487
01488 return 0;
01489 err:
01490 if(rq)
01491 request_free(rq);
01492 return ~0;
01493 }
01494
01495 static int request_unlink_uploads(var_t *v, void * arg)
01496 {
01497 dbg_err_if (v == NULL);
01498
01499 u_unused_args(arg);
01500
01501 if(var_get_opaque(v) && var_get_value(v))
01502 {
01503 unlink(var_get_value(v));
01504 }
01505
01506 err:
01507 return 0;
01508 }
01509
01510 int request_free(request_t *rq)
01511 {
01512 if (rq)
01513 {
01514
01515 request_clear_uri(rq);
01516
01517 if(rq->header)
01518 header_free(rq->header);
01519
01520 if(rq->io)
01521 io_free(rq->io);
01522
01523 if(rq->uploads)
01524 {
01525
01526 vars_foreach(rq->uploads, request_unlink_uploads, NULL);
01527 vars_free(rq->uploads);
01528 }
01529
01530 if(rq->cookies)
01531 vars_free(rq->cookies);
01532
01533 if(rq->args)
01534 vars_free(rq->args);
01535
01536 U_FREE(rq);
01537 }
01538
01539 return 0;
01540 }
01541
01542
01543 int request_set_addr(request_t *rq, addr_t *addr)
01544 {
01545 dbg_return_if (rq == NULL, ~0);
01546 dbg_return_if (addr == NULL, ~0);
01547
01548 memcpy(&rq->local_addr, addr, sizeof(addr_t));
01549
01550 return 0;
01551 }
01552
01553
01554 int request_set_peer_addr(request_t *rq, addr_t *addr)
01555 {
01556 dbg_return_if (rq == NULL, ~0);
01557 dbg_return_if (addr == NULL, ~0);
01558
01559 memcpy(&rq->peer_addr, addr, sizeof(addr_t));
01560
01561 return 0;
01562 }
01563
01573 addr_t* request_get_addr(request_t *rq)
01574 {
01575 dbg_return_if (rq == NULL, NULL);
01576
01577 return &rq->local_addr;
01578 }
01579
01589 addr_t* request_get_peer_addr(request_t *rq)
01590 {
01591 dbg_return_if (rq == NULL, NULL);
01592
01593 return &rq->peer_addr;
01594 }
01595
01606 header_t* request_get_header(request_t *rq)
01607 {
01608 dbg_return_if (rq == NULL, NULL);
01609
01610 return rq->header;
01611 }
01612
01623 field_t* request_get_field(request_t *rq, const char *name)
01624 {
01625 dbg_return_if (rq == NULL, NULL);
01626 dbg_return_if (name == NULL, NULL);
01627
01628 return header_get_field(rq->header, name);
01629 }
01630
01641 const char* request_get_field_value(request_t *rq, const char *name)
01642 {
01643 dbg_return_if (rq == NULL, NULL);
01644 dbg_return_if (name == NULL, NULL);
01645
01646 return header_get_field_value(rq->header, name);
01647 }
01648
01649
01655 int request_set_field(request_t *rq, const char *name, const char *value)
01656 {
01657 dbg_return_if (rq == NULL, ~0);
01658 dbg_return_if (name == NULL, ~0);
01659 dbg_return_if (value == NULL, ~0);
01660
01661 return header_set_field(rq->header, name, value);
01662 }
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674 int request_set_filename(request_t *rq, const char *filename)
01675 {
01676 dbg_err_if (rq == NULL);
01677 dbg_err_if (filename == NULL);
01678
01679 REQUEST_SET_STRING_FIELD(rq->filename, filename);
01680
01681 return 0;
01682 err:
01683 return ~0;
01684 }
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696 int request_set_resolved_filename(request_t *rq, const char *resolved_fn)
01697 {
01698 dbg_err_if (rq == NULL);
01699 dbg_err_if (resolved_fn == NULL);
01700
01701 REQUEST_SET_STRING_FIELD(rq->resolved_filename, resolved_fn);
01702
01703 return 0;
01704 err:
01705 return ~0;
01706 }
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717 int request_set_query_string(request_t *rq, const char *query)
01718 {
01719 dbg_err_if (rq == NULL);
01720 dbg_err_if (query == NULL);
01721
01722 REQUEST_SET_STRING_FIELD(rq->query, query);
01723
01724 return 0;
01725 err:
01726 return ~0;
01727 }
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739 int request_set_path_info(request_t *rq, const char *path_info)
01740 {
01741 dbg_err_if (rq == NULL);
01742 dbg_err_if (path_info == NULL);
01743
01744 REQUEST_SET_STRING_FIELD(rq->path_info, path_info);
01745
01746 return 0;
01747 err:
01748 return ~0;
01749 }
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761 int request_set_resolved_path_info(request_t *rq, const char *resolved_pi)
01762 {
01763 dbg_err_if (rq == NULL);
01764 dbg_err_if (resolved_pi == NULL);
01765
01766 REQUEST_SET_STRING_FIELD(rq->resolved_path_info, resolved_pi);
01767
01768 return 0;
01769 err:
01770 return ~0;
01771 }
01772
01773