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 #include <klone/vhost.h>
00027 #include <klone/supplier.h>
00028
00029 struct request_s
00030 {
00031 http_t *http;
00032 header_t *header;
00033 io_t *io;
00034 int method;
00035 char *cli_rq;
00036 char *uri;
00037 char *protocol;
00038 char *path_info;
00039 char *query;
00040 char *filename;
00041 char *resolved_path_info;
00042 char *resolved_filename;
00043 vars_t *args;
00044 vars_t *args_get;
00045 vars_t *args_post;
00046 vars_t *cookies;
00047 vars_t *uploads;
00048 char *content_type;
00049 char *content_encoding;
00050 size_t content_length;
00051 time_t if_modified_since;
00052 kaddr_t local_addr, peer_addr;
00053 int cgi;
00054 size_t idle_timeout;
00055 size_t post_timeout;
00056 size_t post_maxsize;
00057 const char *temp_dir;
00058 vhost_t *vhost;
00059 size_t padding;
00060
00061 supplier_t *si_sup;
00062 void *si_handle;
00063 time_t si_mtime;
00064 };
00065
00066 typedef struct upload_info_s
00067 {
00068 char mime_type[MIME_TYPE_BUFSZ];
00069 char filename[U_FILENAME_MAX];
00070 size_t size;
00071 } upload_info_t;
00072
00073 enum {
00074 REQUEST_DEFAULT_IDLE_TIMEOUT = 10,
00075 REQUEST_DEFAULT_POST_TIMEOUT = 600,
00076 REQUEST_DEFAULT_POST_MAXSIZE = 5*1024000,
00077 };
00078
00079
00080 #define REQUEST_SET_STRING_FIELD(lval, rval) \
00081 do { \
00082 U_FREE(lval); \
00083 if(rval) \
00084 { \
00085 lval = u_strdup(rval); \
00086 dbg_err_if(lval == NULL); \
00087 } \
00088 } while(0)
00089
00090
00091 int request_is_encoding_accepted(request_t *rq, const char *encoding)
00092 {
00093 char *pp, *tok, *src, *buf = NULL;
00094 const char *accept_encoding;
00095 int rc = 0;
00096
00097 dbg_err_if (rq == NULL);
00098 dbg_err_if (encoding == NULL);
00099
00100 accept_encoding = header_get_field_value(rq->header, "Accept-Encoding");
00101 if(accept_encoding)
00102 {
00103
00104 buf = u_strdup(accept_encoding);
00105 dbg_err_if(buf == NULL);
00106
00107
00108 for(src = buf; (tok = strtok_r(src, " ,", &pp)) != NULL; src = NULL)
00109 {
00110 if(strcasecmp(tok, encoding) == 0)
00111 {
00112 rc++;
00113 break;
00114 }
00115 }
00116
00117 U_FREE(buf);
00118 }
00119
00120 return rc;
00121 err:
00122 U_FREE(buf);
00123 return 0;
00124 }
00125
00141 io_t *request_io(request_t *rq)
00142 {
00143 dbg_return_if (rq == NULL, NULL);
00144
00145 return rq->io;
00146 }
00147
00159 vars_t *request_get_cookies(request_t *rq)
00160 {
00161 dbg_return_if (rq == NULL, NULL);
00162
00163 return rq->cookies;
00164 }
00165
00177 const char *request_get_cookie(request_t *rq, const char *name)
00178 {
00179 var_t *v;
00180
00181 dbg_return_if (rq == NULL, NULL);
00182 dbg_return_if (name == NULL, NULL);
00183
00184 v = vars_get(rq->cookies, name);
00185
00186 return v ? var_get_value(v): NULL;
00187 }
00188
00199 vars_t *request_get_args(request_t *rq)
00200 {
00201 dbg_return_if (rq == NULL, NULL);
00202
00203 return rq->args;
00204 }
00205
00216 vars_t *request_get_getargs(request_t *rq)
00217 {
00218 dbg_return_if (rq == NULL, NULL);
00219
00220 return rq->args_get;
00221 }
00222
00233 vars_t *request_get_postargs(request_t *rq)
00234 {
00235 dbg_return_if (rq == NULL, NULL);
00236
00237 return rq->args_post;
00238 }
00239
00253 const char *request_get_arg(request_t *rq, const char *name)
00254 {
00255 var_t *v;
00256
00257 dbg_return_if (rq == NULL, NULL);
00258 dbg_return_if (name == NULL, NULL);
00259
00260 v = vars_get(rq->args, name);
00261
00262 return v ? var_get_value(v): NULL;
00263 }
00264
00278 const char *request_get_getarg(request_t *rq, const char *name)
00279 {
00280 var_t *v;
00281
00282 dbg_return_if (rq == NULL, NULL);
00283 dbg_return_if (name == NULL, NULL);
00284
00285 v = vars_get(rq->args_get, name);
00286
00287 return v ? var_get_value(v): NULL;
00288 }
00289
00303 const char *request_get_postarg(request_t *rq, const char *name)
00304 {
00305 var_t *v;
00306
00307 dbg_return_if (rq == NULL, NULL);
00308 dbg_return_if (name == NULL, NULL);
00309
00310 v = vars_get(rq->args_post, name);
00311
00312 return v ? var_get_value(v): NULL;
00313 }
00314
00315 int request_set_field(request_t *rq, const char *name, const char *value)
00316 {
00317 dbg_return_if (rq == NULL, ~0);
00318 dbg_return_if (name == NULL, ~0);
00319 dbg_return_if (value == NULL, ~0);
00320
00321 return header_set_field(rq->header, name, value);
00322 }
00323
00334 const char *request_get_uri(request_t *rq)
00335 {
00336 dbg_return_if (rq == NULL, NULL);
00337
00338 return rq->uri;
00339 }
00340
00351 const char *request_get_filename(request_t *rq)
00352 {
00353 dbg_return_if (rq == NULL, NULL);
00354
00355 return rq->filename;
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 int request_set_filename(request_t *rq, const char *filename)
00370 {
00371 dbg_err_if (rq == NULL);
00372 dbg_err_if (filename == NULL);
00373
00374 REQUEST_SET_STRING_FIELD(rq->filename, filename);
00375
00376 return 0;
00377 err:
00378 return ~0;
00379 }
00380
00391 const char *request_get_query_string(request_t *rq)
00392 {
00393 dbg_return_if (rq == NULL, NULL);
00394
00395 return rq->query;
00396 }
00397
00408 const char *request_get_path_info(request_t *rq)
00409 {
00410 dbg_return_if (rq == NULL, NULL);
00411
00412 return rq->path_info;
00413 }
00414
00415
00416 static int request_parse_ims(request_t *rq)
00417 {
00418 const char *ims;
00419
00420 dbg_err_if (rq == NULL);
00421
00422 rq->if_modified_since = 0;
00423
00424 ims = header_get_field_value(rq->header, "If-Modified-Since");
00425 if(ims)
00426 dbg_err_if(u_httpdate_to_tt(ims, &rq->if_modified_since));
00427
00428 err:
00429 return 0;
00430 }
00431
00442 time_t request_get_if_modified_since(request_t *rq)
00443 {
00444 dbg_return_if (rq == NULL, (time_t) -1);
00445
00446 return rq->if_modified_since;
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460 int request_set_resolved_filename(request_t *rq, const char *resolved_fn)
00461 {
00462 dbg_err_if (rq == NULL);
00463 dbg_err_if (resolved_fn == NULL);
00464
00465 REQUEST_SET_STRING_FIELD(rq->resolved_filename, resolved_fn);
00466
00467 return 0;
00468 err:
00469 return ~0;
00470 }
00471
00482 http_t* request_get_http(request_t *rq)
00483 {
00484 dbg_return_if (rq == NULL, NULL);
00485
00486 return rq->http;
00487 }
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 int request_bind(request_t *rq, io_t *in)
00501 {
00502 dbg_return_if (rq == NULL, ~0);
00503 dbg_return_if (in == NULL, ~0);
00504
00505 rq->io = in;
00506
00507 return 0;
00508 }
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 int request_set_query_string(request_t *rq, const char *query)
00522 {
00523 dbg_err_if (rq == NULL);
00524 dbg_err_if (query == NULL);
00525
00526 REQUEST_SET_STRING_FIELD(rq->query, query);
00527
00528 return 0;
00529 err:
00530 return ~0;
00531 }
00532
00533 void request_clear_uri(request_t *rq)
00534 {
00535 U_FREE(rq->uri);
00536 U_FREE(rq->protocol);
00537 U_FREE(rq->path_info);
00538 U_FREE(rq->query);
00539 U_FREE(rq->filename);
00540 U_FREE(rq->resolved_path_info);
00541 U_FREE(rq->resolved_filename);
00542 U_FREE(rq->content_type);
00543 U_FREE(rq->content_encoding);
00544 }
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557 int request_set_path_info(request_t *rq, const char *path_info)
00558 {
00559 dbg_err_if (rq == NULL);
00560 dbg_err_if (path_info == NULL);
00561
00562 REQUEST_SET_STRING_FIELD(rq->path_info, path_info);
00563
00564 return 0;
00565 err:
00566 return ~0;
00567 }
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 int request_set_resolved_path_info(request_t *rq, const char *resolved_pi)
00581 {
00582 dbg_err_if (rq == NULL);
00583 dbg_err_if (resolved_pi == NULL);
00584
00585 REQUEST_SET_STRING_FIELD(rq->resolved_path_info, resolved_pi);
00586
00587 return 0;
00588 err:
00589 return ~0;
00590 }
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 int request_set_uri(request_t *rq, const char *uri,
00606 int (*is_valid_uri)(void*, const char *, size_t),
00607 void* arg)
00608 {
00609 char *p, *fn, *pi;
00610 size_t uri_len = strlen(uri);
00611 char cp[4096];
00612
00613 dbg_err_if (rq == NULL);
00614 dbg_err_if (uri == NULL);
00615
00616
00617
00618 request_clear_uri(rq);
00619
00620
00621
00622 warn_err_ifm(uri_len >= sizeof(cp), "Request URI too long");
00623
00624 REQUEST_SET_STRING_FIELD(rq->uri, uri);
00625
00626
00627 if((p = strchr(uri, '?')) != NULL)
00628 dbg_err_if(request_set_query_string(rq, ++p));
00629
00630
00631 dbg_err_if(u_urlncpy(cp, rq->uri, uri_len, URLCPY_DECODE) <= 0);
00632
00633 if((p = strchr(cp, '?')) != NULL)
00634 *p++ = 0;
00635
00636
00637 dbg_err_if(u_uri_normalize(cp));
00638
00639
00640 dbg_err_if(request_set_filename(rq, cp));
00641
00642
00643 fn = cp;
00644 pi = fn + strlen(fn);
00645 for(;;)
00646 {
00647 if(is_valid_uri == NULL || is_valid_uri(arg, fn, pi - fn))
00648 {
00649 dbg_err_if(request_set_filename(rq, fn));
00650 rq->filename[pi-fn] = 0;
00651 if(strlen(pi))
00652 dbg_err_if(request_set_path_info(rq, pi));
00653 break;
00654 } else {
00655 if((p = u_strnrchr(fn, '/', pi - fn)) == NULL)
00656 break;
00657 pi = p;
00658 }
00659 }
00660
00661 return 0;
00662 err:
00663 return ~0;
00664 }
00665
00666 static int request_set_proto(request_t *rq, const char *proto)
00667 {
00668 dbg_err_if (rq == NULL);
00669 dbg_err_if (proto == NULL);
00670
00671
00672 if(strncasecmp(proto, "http", 4))
00673 return ~0;
00674
00675 REQUEST_SET_STRING_FIELD(rq->protocol, proto);
00676
00677 return 0;
00678 err:
00679 return ~0;
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 int request_set_client_request(request_t *rq, const char *ln)
00694 {
00695 char *p;
00696 dbg_err_if(rq == NULL);
00697 dbg_err_if(ln == NULL);
00698
00699 rq->cli_rq = u_strdup(ln);
00700 dbg_err_if(rq->cli_rq == NULL);
00701
00702
00703 for(p = rq->cli_rq; *p && (*p != '\r' && *p != '\n'); ++p)
00704 continue;
00705 *p = 0;
00706
00707 return 0;
00708 err:
00709 return ~0;
00710 }
00711
00722 const char *request_get_client_request(request_t *rq)
00723 {
00724 return rq->cli_rq;
00725 }
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735 int request_set_method(request_t *rq, const char *method)
00736 {
00737 dbg_return_if (rq == NULL, ~0);
00738 dbg_return_if (method == NULL, ~0);
00739
00740 if(!strcasecmp(method, "get"))
00741 rq->method = HM_GET;
00742 else if(!strcasecmp(method, "head"))
00743 rq->method = HM_HEAD;
00744 else if(!strcasecmp(method, "post"))
00745 rq->method = HM_POST;
00746 else if(!strcasecmp(method, "put"))
00747 rq->method = HM_PUT;
00748 else if(!strcasecmp(method, "delete"))
00749 rq->method = HM_DELETE;
00750 else {
00751
00752 rq->method = HM_UNKNOWN;
00753 return ~0;
00754 }
00755
00756 return 0;
00757 }
00758
00759 static int request_set_content_length(request_t *rq)
00760 {
00761 const char *clen;
00762 size_t len;
00763
00764 dbg_err_if (rq == NULL);
00765
00766 clen = header_get_field_value(rq->header, "Content-Length");
00767 dbg_err_if(clen == NULL || (len = atoi(clen)) < 0);
00768
00769 rq->content_length = len;
00770
00771 return 0;
00772 err:
00773 return ~0;
00774 }
00775
00776 static int request_parse_cookie(request_t *rq, field_t *field)
00777 {
00778 enum { BUFSZ = 4096 };
00779 char *pp, *tok, *src, buf[BUFSZ];
00780
00781 dbg_err_if (rq == NULL);
00782 dbg_err_if (field == NULL);
00783
00784 dbg_err_if(field_get_value(field) == NULL);
00785
00786
00787 strncpy(buf, field_get_value(field), BUFSZ);
00788
00789
00790 for(src = buf; (tok = strtok_r(src, " ;", &pp)) != NULL; src = NULL)
00791 dbg_if(vars_add_urlvar(rq->cookies, tok, NULL));
00792
00793 return 0;
00794 err:
00795 return ~0;
00796 }
00797
00798 static int request_parse_cookies(request_t *rq)
00799 {
00800 field_t *f;
00801 size_t i, count;
00802
00803 dbg_err_if (rq == NULL);
00804
00805 count = header_field_count(rq->header);
00806 for(i = 0; i < count; ++i)
00807 {
00808 f = header_get_fieldn(rq->header, i);
00809 dbg_err_if(f == NULL);
00810 if(strcasecmp(field_get_name(f), "cookie") == 0)
00811 dbg_err_if(request_parse_cookie(rq, f));
00812 }
00813
00814 return 0;
00815 err:
00816 return ~0;
00817 }
00818
00819 static int request_cb_add_var(vars_t *args, vars_t *also_to, const char *tok)
00820 {
00821 var_t *v = NULL;
00822
00823 dbg_err_if(args == NULL);
00824 dbg_err_if(also_to == NULL);
00825 dbg_err_if(tok == NULL);
00826
00827
00828 dbg_if(vars_add_urlvar(args, tok, &v));
00829
00830 if(v)
00831 {
00832
00833 dbg_err_if(vars_add(also_to, v));
00834 }
00835
00836 return 0;
00837 err:
00838 return ~0;
00839 }
00840
00841
00842 static int request_cb_add_post_var(void *arg, const char *tok)
00843 {
00844 request_t *rq = (request_t*)arg;
00845
00846 return request_cb_add_var(rq->args, rq->args_post, tok);
00847 }
00848
00849 static int request_cb_add_get_var(void *arg, const char *tok)
00850 {
00851 request_t *rq = (request_t*)arg;
00852
00853 return request_cb_add_var(rq->args, rq->args_get, tok);
00854 }
00855
00856 static int foreach_query_var(const char *urlquery, int offset,
00857 int(*cb)(void*,const char*), void *arg)
00858 {
00859 char *pp, *tok, *src, *query = NULL;
00860
00861 dbg_err_if(offset < 0);
00862 dbg_err_if(cb == NULL);
00863
00864 if(!urlquery)
00865 return 0;
00866
00867
00868 query = u_strdup(urlquery + offset);
00869 dbg_err_if(query == NULL);
00870
00871
00872 for(src = query; (tok = strtok_r(src, "&", &pp)) != NULL; src = NULL)
00873 {
00874
00875 dbg_err_if(cb(arg, tok));
00876 }
00877
00878 U_FREE(query);
00879
00880 return 0;
00881 err:
00882 U_FREE(query);
00883 return ~0;
00884 }
00885
00886 static int request_parse_query_args(request_t *rq)
00887 {
00888 dbg_err_if(rq == NULL);
00889
00890 return foreach_query_var(rq->query, 0, request_cb_add_get_var, (void*)rq);
00891 err:
00892 return ~0;
00893 }
00894
00895
00896 void request_set_cgi(request_t *rq, int cgi)
00897 {
00898 rq->cgi = cgi;
00899 return;
00900 }
00901
00913 ssize_t request_get_content_length(request_t *rq)
00914 {
00915 dbg_return_if (rq == NULL, -1);
00916
00917 return (ssize_t) rq->content_length;
00918 }
00919
00920 static int match_content_type(header_t *h, const char *mime_type)
00921 {
00922 const char *ct;
00923
00924 dbg_return_if (h == NULL, 0);
00925 dbg_return_if (mime_type == NULL, 0);
00926
00927 ct = header_get_field_value(h, "Content-Type");
00928 if(ct == NULL || strncasecmp(ct, mime_type, strlen(mime_type)))
00929 return 0;
00930
00931 return 1;
00932 }
00933
00934 static int request_is_content_type(request_t *rq, const char *ct)
00935 {
00936 return match_content_type(rq->header, ct);
00937 }
00938
00939 static int request_is_multipart_formdata(request_t *rq)
00940 {
00941 return request_is_content_type(rq, "multipart/form-data");
00942 }
00943
00944 static int request_is_urlencoded(request_t *rq)
00945 {
00946 if(header_get_field_value(rq->header, "Content-Type") == NULL)
00947 return 1;
00948
00949 if(request_is_content_type(rq, "application/x-www-form-urlencoded"))
00950 return 1;
00951
00952 return 0;
00953 }
00954
00955 static int request_parse_urlencoded_data(request_t *rq)
00956 {
00957 ssize_t qsz, len;
00958
00959 dbg_err_if (rq == NULL);
00960
00961 len = rq->content_length;
00962
00963 qsz = (rq->query ? strlen(rq->query) : 0);
00964
00965
00966 rq->query = u_realloc(rq->query, len + qsz + 2);
00967 dbg_err_if(rq->query == NULL);
00968
00969
00970
00971 rq->query[qsz] = 0;
00972 if(qsz)
00973 {
00974 strcat(rq->query, "&");
00975 ++qsz;
00976 }
00977
00978
00979 dbg_err_if(io_read(rq->io, rq->query + qsz, len) != len);
00980
00981
00982 rq->query[qsz + len] = 0;
00983
00984
00985 dbg_err_if(foreach_query_var(rq->query, qsz,
00986 request_cb_add_post_var, (void*)rq));
00987
00988 return 0;
00989 err:
00990 return ~0;
00991 }
00992
00993
00994
00995 static int request_get_fieldparam(request_t *rq, const char *field_name,
00996 const char *param_name, char *buf, size_t size)
00997 {
00998 const char *param_value, *field_value, *p;
00999 size_t pv_len;
01000
01001 dbg_err_if (rq == NULL);
01002 dbg_err_if (field_name == NULL);
01003 dbg_err_if (param_name == NULL);
01004 dbg_err_if (buf == NULL);
01005 dbg_err_if (size == 0);
01006
01007 field_value = header_get_field_value(rq->header, field_name);
01008 dbg_err_if(field_value == NULL);
01009
01010
01011 param_value = u_stristr(field_value, param_name);
01012 dbg_err_if(param_value == NULL);
01013
01014
01015 param_value += strlen(param_name);
01016
01017
01018 dbg_err_if(*param_value++ != '=');
01019
01020
01021 for(p = param_value; ;++p)
01022 if(*p == '\0' || *p == ';' || isspace(*p))
01023 break;
01024
01025
01026 pv_len = p - param_value;
01027
01028
01029 dbg_err_if(pv_len > size - 1);
01030
01031
01032 strncpy(buf, param_value, pv_len);
01033 buf[MIN(pv_len, size - 1)] = 0;
01034
01035 return 0;
01036 err:
01037 return ~0;
01038 }
01039
01040 static int is_multipart_mixed(header_t *h)
01041 {
01042 return match_content_type(h, "multipart/mixed");
01043 }
01044
01045 static int is_encoded(header_t *h)
01046 {
01047 const char *cte;
01048
01049 dbg_return_if (h == NULL, 0);
01050
01051 if((cte = header_get_field_value(h, "Content-Transfer-Encoding")) == NULL)
01052 return 0;
01053
01054 if(strcasecmp(cte, "binary") == 0)
01055 return 0;
01056
01057 return 1;
01058 }
01059
01060 static inline int is_nl(char c)
01061 {
01062 return (c == '\n' || c == '\r' ? c : 0);
01063 }
01064
01065 static inline int is_quote(char c)
01066 {
01067 return (c == '"' || c == '\'' ? c : 0);
01068 }
01069
01070 static int parse_content_disposition(header_t *h, char *name, char *filename,
01071 size_t prmsz)
01072 {
01073 enum { BUFSZ = 512 };
01074 char *pp, *tok, *src, buf[BUFSZ];
01075 size_t n_len, fn_len;
01076 const char *cd;
01077 int q;
01078
01079 dbg_err_if (h == NULL);
01080 dbg_err_if (name == NULL);
01081 dbg_err_if (filename == NULL);
01082 dbg_err_if (prmsz == 0);
01083
01084 cd = header_get_field_value(h, "Content-Disposition");
01085 dbg_err_if(cd == NULL);
01086
01087 dbg_err_if(strlen(cd) >= BUFSZ);
01088
01089
01090 dbg_err_if(strncmp(cd, "form-data", strlen("form-data")));
01091
01092 name[0] = filename[0] = 0;
01093
01094
01095 strncpy(buf, cd, BUFSZ);
01096
01097
01098 n_len = strlen("name=");
01099 fn_len = strlen("filename=");
01100
01101
01102 for(src = buf; (tok = strtok_r(src, ";", &pp)) != NULL; src = NULL)
01103 {
01104
01105 while(isspace(*tok))
01106 ++tok;
01107
01108 if(strncmp(tok, "form-data", strlen("form-data")) == 0)
01109 continue;
01110 else if(strncmp(tok, "name=", n_len) == 0) {
01111
01112 tok += n_len;
01113
01114
01115 if((q = is_quote(tok[0])) != 0)
01116 ++tok;
01117 if(strlen(tok) && tok[strlen(tok) - 1] == q)
01118 tok[strlen(tok) - 1] = 0;
01119
01120 strncpy(name, tok, prmsz);
01121 } else if(strncmp(tok, "filename=", fn_len) == 0) {
01122
01123 tok += fn_len;
01124
01125
01126 if((q = is_quote(tok[0])) != 0)
01127 ++tok;
01128 if(strlen(tok) && tok[strlen(tok) - 1] == q)
01129 tok[strlen(tok) - 1] = 0;
01130
01131 strncpy(filename, tok, prmsz);
01132 }
01133
01134 }
01135
01136 return 0;
01137 err:
01138 return ~0;
01139 }
01140
01141
01142
01143
01144
01145
01146
01147
01148 static ssize_t read_until(io_t *io, const char *stop_at, char *obuf,
01149 size_t size, int *found)
01150 {
01151
01152
01153
01154 #define SETUP_BUF_ACCESS_AT(idx) \
01155 if(idx >= wtot) { \
01156 if(idx >= size) \
01157 return wtot; \
01158 \
01159 \
01160 dbg_err_if((rc = io_read(io, wbuf, idx + 1 - wtot)) < 0); \
01161 if(rc == 0 || rc < idx + 1 - wtot) \
01162 return wtot + rc; \
01163 wbuf += rc; \
01164 wtot += rc; \
01165 }
01166
01167 int sa_len = strlen(stop_at);
01168 int i, t, shift[256], rc;
01169 unsigned char c;
01170 size_t wtot = 0;
01171 char *wbuf = obuf;
01172
01173 dbg_err_if (io == NULL);
01174 dbg_err_if (stop_at == NULL);
01175 dbg_err_if (obuf == NULL);
01176
01177 dbg_err_if (found == NULL);
01178
01179 for(i = 0; i < 256; ++i)
01180 shift[i] = sa_len;
01181
01182 for(i = 0; i < sa_len; ++i)
01183 shift[ (int)stop_at[i] ] = sa_len - i - 1;
01184
01185 *found = 0;
01186
01187 for(i = t = sa_len-1; t >= 0; --i, --t)
01188 {
01189 SETUP_BUF_ACCESS_AT(i);
01190
01191 while((c = obuf[i]) != stop_at[t])
01192 {
01193 i += MAX(sa_len - t, shift[c]);
01194
01195 SETUP_BUF_ACCESS_AT(i);
01196
01197 t = sa_len - 1;
01198 }
01199 }
01200
01201 *found = 1;
01202
01203
01204 return wtot;
01205 err:
01206 return -1;
01207 }
01208
01209
01228 vars_t *request_get_uploads(request_t *rq)
01229 {
01230 return rq->uploads;
01231 }
01232
01233
01234
01235
01236
01237
01238
01239
01240 static int request_add_uploaded_file(request_t *rq, const char *name,
01241 const char *filename, const char *tmp_filename, const char *mime_type)
01242 {
01243 struct stat st;
01244 var_t *v = NULL;
01245 upload_info_t *info = NULL;
01246
01247 dbg_err_if (rq == NULL);
01248 dbg_err_if (name == NULL);
01249
01250 dbg_err_if (tmp_filename == NULL);
01251
01252
01253 dbg_err_sif (stat(tmp_filename, &st) < 0);
01254
01255
01256 dbg_err_if(var_create(name, tmp_filename, &v));
01257
01258
01259 dbg_err_if((info = u_zalloc(sizeof(upload_info_t))) == NULL);
01260
01261
01262 info->size = st.st_size;
01263 if(mime_type)
01264 snprintf(info->mime_type, MIME_TYPE_BUFSZ, "%s", mime_type);
01265 else
01266 info->mime_type[0] = 0;
01267
01268 if(filename)
01269 snprintf(info->filename, U_FILENAME_MAX, "%s", filename);
01270
01271
01272 var_set_opaque(v, info);
01273 info = NULL;
01274
01275
01276 dbg_err_if(vars_add(rq->uploads, v));
01277
01278 return 0;
01279 err:
01280 if(info)
01281 U_FREE(info);
01282 if(v)
01283 var_free(v);
01284 return ~0;
01285 }
01286
01287 static int request_get_uploaded_filev(request_t *rq, var_t *v,
01288 char local_filename[U_FILENAME_MAX], char client_filename[U_FILENAME_MAX],
01289 char mime_type[MIME_TYPE_BUFSZ], size_t *file_size)
01290 {
01291 upload_info_t *info;
01292 const char *tmp_fqn;
01293
01294 dbg_err_if (rq == NULL);
01295 dbg_err_if (v == NULL);
01296 dbg_err_if (local_filename == NULL);
01297 dbg_err_if (client_filename == NULL);
01298 dbg_err_if (mime_type == NULL);
01299 dbg_err_if (file_size == NULL);
01300
01301 info = var_get_opaque(v);
01302 dbg_err_if(info == NULL);
01303
01304 tmp_fqn = var_get_value(v);
01305 dbg_err_if(tmp_fqn == NULL);
01306
01307
01308 strncpy(local_filename, tmp_fqn, U_FILENAME_MAX);
01309 strncpy(mime_type, info->mime_type, MIME_TYPE_BUFSZ);
01310 strncpy(client_filename, info->filename, U_FILENAME_MAX);
01311 *file_size = info->size;
01312
01313 return 0;
01314 err:
01315 return ~0;
01316 }
01317
01340 int request_get_uploaded_file(request_t *rq, const char *name, size_t idx,
01341 char local_filename[U_FILENAME_MAX], char client_filename[U_FILENAME_MAX],
01342 char mime_type[MIME_TYPE_BUFSZ], size_t *file_size)
01343 {
01344 var_t *v;
01345
01346 dbg_err_if (rq == NULL);
01347 dbg_err_if (name == NULL);
01348 dbg_err_if (idx >= vars_count(rq->uploads));
01349 dbg_err_if (local_filename == NULL);
01350 dbg_err_if (client_filename == NULL);
01351 dbg_err_if (mime_type == NULL);
01352 dbg_err_if (file_size == NULL);
01353
01354 v = vars_geti(rq->uploads, name, idx);
01355 dbg_err_if(v == NULL);
01356
01357 return request_get_uploaded_filev(rq, v, local_filename, client_filename,
01358 mime_type, file_size);
01359 err:
01360 return ~0;
01361 }
01362
01363 static ssize_t request_read_until_boundary(request_t *rq, io_t *io,
01364 const char *boundary, char *buf, size_t size, u_buf_t **pubuf)
01365 {
01366 u_buf_t *ubuf = NULL;
01367 int found;
01368 size_t bound_len, trb;
01369 ssize_t rc;
01370
01371
01372 bound_len = strlen(boundary);
01373
01374 trb = 0;
01375
01376 for(found = 0; !found; )
01377 {
01378 rc = read_until(io, boundary, buf, size, &found);
01379 dbg_err_if(rc <= 0);
01380
01381
01382 if(found)
01383 {
01384 rc -= (bound_len + 2);
01385 dbg_err_if(rc < 0);
01386
01387
01388 buf[rc] = 0;
01389
01390 } else {
01391
01392
01393 if(ubuf == NULL)
01394 {
01395 dbg_err_if(u_buf_create(&ubuf));
01396 dbg_err_if(u_buf_reserve(ubuf, 2 * size));
01397 }
01398 }
01399
01400
01401 trb += rc;
01402
01403 warn_err_ifm(trb > rq->post_maxsize, "POST data exceed post_maxsize");
01404
01405
01406 if(ubuf)
01407 dbg_err_if(u_buf_append(ubuf, buf, rc));
01408 }
01409
01410 *pubuf = ubuf;
01411
01412 return (ubuf ? u_buf_len(ubuf) : rc);
01413 err:
01414 if(ubuf)
01415 u_buf_free(ubuf);
01416 return -1;
01417
01418 }
01419
01420 static int request_parse_multipart_chunk(request_t *rq, io_t *io,
01421 const char *boundary, int *eof)
01422 {
01423 enum { PRMSZ = 512, BUFSZ = 4096 };
01424 header_t *h = NULL;
01425 io_t *tmpio = NULL;
01426 var_t *v = NULL;
01427 u_buf_t *ubuf = NULL;
01428 char name[PRMSZ], filename[PRMSZ], buf[BUFSZ];
01429 size_t bound_len;
01430 int found;
01431 ssize_t rc;
01432
01433
01434 dbg_err_if(header_create(&h));
01435
01436
01437 dbg_err_if(header_load(h, io));
01438
01439 warn_err_ifm(is_multipart_mixed(h),
01440 "multipart/mixed content is not supported yet");
01441
01442
01443 warn_err_ifm(is_encoded(h),
01444 "encoded file upload is not supported");
01445
01446 dbg_err_if(parse_content_disposition(h, name, filename, PRMSZ));
01447
01448
01449 bound_len = strlen(boundary);
01450
01451 if(filename[0] != '\0')
01452 {
01453 dbg_err_if(BUFSZ <= bound_len);
01454
01455
01456 dbg_err_if(u_tmpfile_open(rq->temp_dir, &tmpio));
01457
01458 for(found = 0; !found; )
01459 {
01460 rc = read_until(io, boundary, buf, BUFSZ, &found);
01461 dbg_err_if(rc <= 0);
01462
01463
01464 if(found)
01465 {
01466 rc -= (bound_len + 2);
01467 dbg_err_if(rc < 0);
01468 }
01469
01470
01471 dbg_err_if(io_write(tmpio, buf, rc) < 0);
01472 }
01473
01474
01475 dbg_err_if(io_name_get(tmpio, buf, BUFSZ));
01476
01477
01478 io_free(tmpio); tmpio = NULL;
01479
01480
01481 dbg_err_if(request_add_uploaded_file(rq, name, filename, buf,
01482 header_get_field_value(h, "Content-Type")));
01483
01484
01485 dbg_err_if(io_gets(io, buf, BUFSZ) <= 0);
01486
01487 if(strncmp(buf, "--", 2) == 0)
01488 *eof = 1;
01489
01490 } else {
01491
01492
01493
01494 rc = request_read_until_boundary(rq, io, boundary, buf, BUFSZ, &ubuf);
01495 dbg_err_if(rc < 0);
01496
01497
01498 dbg_err_if(var_bin_create(name,
01499 (ubuf ? u_buf_ptr(ubuf) : buf),
01500 (ubuf ? u_buf_len(ubuf) : rc),
01501 &v));
01502
01503 dbg_if(vars_add(rq->args, v));
01504
01505
01506 dbg_if(vars_add(rq->args_post, v));
01507
01508
01509 dbg_err_if(io_gets(io, buf, BUFSZ) <= 0);
01510
01511 if(strncmp(buf, "--", 2) == 0)
01512 *eof = 1;
01513 }
01514
01515 if(ubuf)
01516 u_buf_free(ubuf);
01517
01518 header_free(h);
01519
01520 return 0;
01521 err:
01522 if(ubuf)
01523 u_buf_free(ubuf);
01524 if(tmpio)
01525 io_free(tmpio);
01526 if(h)
01527 header_free(h);
01528 return ~0;
01529 }
01530
01531 static int request_parse_multipart_data(request_t *rq)
01532 {
01533 enum { BOUNDARY_BUFSZ = 128, BUFSZ = 1024 };
01534 char boundary[BOUNDARY_BUFSZ], buf[BUFSZ];
01535 int eof;
01536
01537
01538 strcpy(boundary, "--");
01539
01540 dbg_err_if(request_get_fieldparam(rq, "Content-Type", "boundary",
01541 boundary + 2, BOUNDARY_BUFSZ - 2));
01542
01543 dbg_err_if(strlen(boundary) == 0);
01544
01545
01546 for(;;)
01547 {
01548 dbg_err_if(io_gets(rq->io, buf, BUFSZ) <= 0);
01549 if(!strncmp(buf, boundary, strlen(boundary)))
01550 break;
01551 }
01552
01553
01554 for(eof = 0; eof == 0; )
01555 dbg_err_if(request_parse_multipart_chunk(rq, rq->io, boundary, &eof));
01556
01557 return 0;
01558 err:
01559 return ~0;
01560 }
01561
01562 static int request_cb_close_socket(talarm_t *al, void *arg)
01563 {
01564 io_t *io = (io_t*)arg;
01565
01566 u_unused_args(al);
01567
01568 warn("[%x] connection timed out, closing", io);
01569
01570
01571 io_close(io);
01572
01573 return 0;
01574 }
01575
01576 int request_parse_data(request_t *rq)
01577 {
01578 talarm_t *al = NULL;
01579 int rc = HTTP_STATUS_BAD_REQUEST;
01580
01581 if(rq->method == HM_POST)
01582 {
01583
01584 dbg_err_if(request_parse_query_args(rq));
01585
01586
01587 dbg_err_if(request_set_content_length(rq) &&
01588 (rc = HTTP_STATUS_LENGTH_REQUIRED));
01589
01590 if(rq->content_length == 0)
01591 return 0;
01592
01593
01594 dbg_err_if(timerm_add(rq->post_timeout, request_cb_close_socket,
01595 (void*)rq->io, &al));
01596
01597
01598 dbg_err_if(rq->content_length > rq->post_maxsize &&
01599 (rc = HTTP_STATUS_REQUEST_TOO_LARGE));
01600
01601 if(request_is_multipart_formdata(rq))
01602 {
01603
01604 dbg_err_if(request_parse_multipart_data(rq));
01605 } else if(request_is_urlencoded(rq)) {
01606
01607
01608 dbg_err_if(request_parse_urlencoded_data(rq));
01609 } else {
01610
01611 }
01612
01613
01614 dbg_if(timerm_del(al)); al = NULL;
01615 } else {
01616
01617 dbg_err_if(request_parse_query_args(rq));
01618 }
01619
01620 return 0;
01621 err:
01622 if(al)
01623 dbg_if(timerm_del(al));
01624 return rc;
01625 }
01626
01627
01628
01629 void request_set_sup_info(request_t *rq, supplier_t *sup, void *handle,
01630 time_t mtime)
01631 {
01632 rq->si_sup = sup;
01633 rq->si_handle = handle;
01634 rq->si_mtime = mtime;
01635
01636 return;
01637 }
01638
01639 void request_get_sup_info(request_t *rq, supplier_t **psup, void **phandle,
01640 time_t *pmtime)
01641 {
01642 if(psup)
01643 *psup = rq->si_sup;
01644
01645 if(phandle)
01646 *phandle = rq->si_handle;
01647
01648 if(pmtime)
01649 *pmtime = rq->si_mtime;
01650
01651 return;
01652 }
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663 int request_parse_header(request_t *rq,
01664 int (*is_valid_uri)(void*, const char *, size_t),
01665 void* arg)
01666 {
01667 enum { BUFSZ = 4096 };
01668 const char WP[] = " \t\r\n";
01669 char ln[BUFSZ], *pp, *method, *uri, *proto;
01670 talarm_t *al = NULL;
01671
01672 dbg_err_if (rq == NULL);
01673 dbg_err_if (rq->io == NULL);
01674
01675
01676 dbg_err_if(timerm_add(rq->idle_timeout, request_cb_close_socket,
01677 (void*)rq->io, &al));
01678
01679 if(!rq->cgi)
01680 {
01681
01682 dbg_err_if(io_gets(rq->io, ln, BUFSZ) <= 0);
01683
01684
01685 dbg_err_if(request_set_client_request(rq, ln));
01686
01687 method = strtok_r(ln, WP, &pp);
01688 dbg_err_if(!method || request_set_method(rq, method));
01689
01690 uri = strtok_r(NULL, WP, &pp);
01691 dbg_err_if(!uri || request_set_uri(rq, uri, is_valid_uri, arg));
01692
01693
01694 proto = strtok_r(NULL, WP, &pp);
01695 dbg_err_if(!proto || request_set_proto(rq, proto));
01696
01697 dbg_err_if(header_load(rq->header, rq->io));
01698 } else {
01699 dbg_err_if(header_load_from_cgienv(rq->header));
01700 }
01701
01702
01703 dbg_err_if(request_parse_ims(rq));
01704
01705
01706 dbg_err_if(request_parse_cookies(rq));
01707
01708
01709 if(request_get_method(rq) == HM_POST)
01710 dbg_err_if(request_set_content_length(rq));
01711
01712
01713 dbg_if(timerm_del(al)); al = NULL;
01714
01715 return 0;
01716 err:
01717 if(al)
01718 timerm_del(al);
01719 return ~0;
01720 }
01721
01733 int request_get_method(request_t *rq)
01734 {
01735 dbg_return_if (rq == NULL, HM_UNKNOWN);
01736
01737 return rq->method;
01738 }
01739
01751 const char* request_get_protocol(request_t *rq)
01752 {
01753 dbg_return_if (rq == NULL, "unknown");
01754
01755 return rq->protocol;
01756 }
01757
01768 const char *request_get_resolved_filename(request_t *rq)
01769 {
01770 dbg_return_if (rq == NULL, NULL);
01771
01772 return rq->resolved_filename;
01773 }
01774
01785 const char *request_get_resolved_path_info(request_t *rq)
01786 {
01787 dbg_return_if (rq == NULL, NULL);
01788
01789 return rq->resolved_path_info;
01790 }
01791
01792 int request_print(request_t *rq)
01793 {
01794 dbg_return_if (rq == NULL, ~0);
01795
01796 dbg("method: %u", rq->method);
01797 dbg("uri: %s", rq->uri);
01798 dbg("proto: %s", rq->protocol);
01799 dbg("filename: %s", rq->filename);
01800 dbg("resolved filename: %s", rq->resolved_filename);
01801 dbg("path_info: %s", rq->path_info);
01802 dbg("resolved path_info: %s", rq->resolved_path_info);
01803 dbg("query: %s", rq->query);
01804
01805 return 0;
01806 }
01807
01808 static int request_load_config(request_t *rq)
01809 {
01810 u_config_t *c;
01811 vhost_t *vhost;
01812 const char *v;
01813
01814 dbg_err_if (rq == NULL);
01815 dbg_err_if (rq->http == NULL);
01816
01817 dbg_err_if((vhost = http_get_vhost(rq->http, rq)) == NULL);
01818
01819
01820 dbg_err_if((c = vhost->config) == NULL);
01821
01822
01823 rq->idle_timeout = REQUEST_DEFAULT_IDLE_TIMEOUT;
01824 rq->post_timeout = REQUEST_DEFAULT_POST_TIMEOUT;
01825 rq->post_maxsize = REQUEST_DEFAULT_POST_MAXSIZE;
01826 rq->temp_dir = NULL;
01827
01828
01829 if((v = u_config_get_subkey_value(c, "idle_timeout")) != NULL)
01830 rq->idle_timeout = MAX(1, atoi(v));
01831
01832
01833 if((v = u_config_get_subkey_value(c, "post_timeout")) != NULL)
01834 rq->post_timeout = MAX(5, atoi(v));
01835
01836
01837 if((v = u_config_get_subkey_value(c, "post_maxsize")) != NULL)
01838 rq->post_maxsize = MAX(1024, atoi(v));
01839
01840
01841 rq->temp_dir = u_config_get_subkey_value(c, "temp_dir");
01842
01843 return 0;
01844 err:
01845 return ~0;
01846 }
01847
01848 int request_create(http_t *http, request_t **prq)
01849 {
01850 request_t *rq = NULL;
01851
01852 dbg_return_if (prq == NULL, ~0);
01853 dbg_return_if (http == NULL, ~0);
01854
01855 rq = u_zalloc(sizeof(request_t));
01856 dbg_err_if(rq == NULL);
01857
01858 dbg_err_if(header_create(&rq->header));
01859
01860 dbg_err_if(vars_create(&rq->args));
01861 dbg_err_if(vars_create(&rq->cookies));
01862 dbg_err_if(vars_create(&rq->uploads));
01863
01864 dbg_err_if(vars_create(&rq->args_get));
01865 dbg_err_if(vars_create(&rq->args_post));
01866
01867
01868 dbg_err_if(vars_set_flags(rq->args_get, VARS_FLAG_FOREIGN));
01869 dbg_err_if(vars_set_flags(rq->args_post, VARS_FLAG_FOREIGN));
01870
01871 rq->http = http;
01872
01873 dbg_err_if(request_load_config(rq));
01874
01875 *prq = rq;
01876
01877 return 0;
01878 err:
01879 if(rq)
01880 request_free(rq);
01881 return ~0;
01882 }
01883
01884 static int request_unlink_uploads(var_t *v, void * arg)
01885 {
01886 dbg_err_if (v == NULL);
01887
01888 u_unused_args(arg);
01889
01890 if(var_get_opaque(v) && var_get_value(v))
01891 {
01892 u_remove(var_get_value(v));
01893 }
01894
01895 err:
01896 return 0;
01897 }
01898
01899 int request_free(request_t *rq)
01900 {
01901 if (rq)
01902 {
01903
01904 request_clear_uri(rq);
01905
01906
01907 U_FREE(rq->cli_rq);
01908
01909 if(rq->header)
01910 header_free(rq->header);
01911
01912 if(rq->io)
01913 io_free(rq->io);
01914
01915 if(rq->uploads)
01916 {
01917
01918 vars_foreach(rq->uploads, request_unlink_uploads, NULL);
01919 vars_free(rq->uploads);
01920 }
01921
01922 if(rq->cookies)
01923 vars_free(rq->cookies);
01924
01925 if(rq->args_get)
01926 vars_free(rq->args_get);
01927
01928 if(rq->args_post)
01929 vars_free(rq->args_post);
01930
01931 if(rq->args)
01932 vars_free(rq->args);
01933
01934 U_FREE(rq);
01935 }
01936
01937 return 0;
01938 }
01939
01940
01941 int request_set_addr(request_t *rq, kaddr_t *addr)
01942 {
01943 dbg_return_if (rq == NULL, ~0);
01944 dbg_return_if (addr == NULL, ~0);
01945
01946 memcpy(&rq->local_addr, addr, sizeof(kaddr_t));
01947
01948 return 0;
01949 }
01950
01951
01952 int request_set_peer_addr(request_t *rq, kaddr_t *addr)
01953 {
01954 dbg_return_if (rq == NULL, ~0);
01955 dbg_return_if (addr == NULL, ~0);
01956
01957 memcpy(&rq->peer_addr, addr, sizeof(kaddr_t));
01958
01959 return 0;
01960 }
01961
01972 kaddr_t* request_get_addr(request_t *rq)
01973 {
01974 dbg_return_if (rq == NULL, NULL);
01975
01976 return &rq->local_addr;
01977 }
01978
01989 kaddr_t* request_get_peer_addr(request_t *rq)
01990 {
01991 dbg_return_if (rq == NULL, NULL);
01992
01993 return &rq->peer_addr;
01994 }
01995
02007 header_t* request_get_header(request_t *rq)
02008 {
02009 dbg_return_if (rq == NULL, NULL);
02010
02011 return rq->header;
02012 }
02013
02025 field_t* request_get_field(request_t *rq, const char *name)
02026 {
02027 dbg_return_if (rq == NULL, NULL);
02028 dbg_return_if (name == NULL, NULL);
02029
02030 return header_get_field(rq->header, name);
02031 }
02032
02044 const char* request_get_field_value(request_t *rq, const char *name)
02045 {
02046 dbg_return_if (rq == NULL, NULL);
02047 dbg_return_if (name == NULL, NULL);
02048
02049 return header_get_field_value(rq->header, name);
02050 }
02051
02052 vhost_t* request_get_vhost(request_t *rq)
02053 {
02054 dbg_return_if (rq == NULL, NULL);
02055
02056 return rq->vhost;
02057 }
02058
02059 int request_set_vhost(request_t *rq, vhost_t *vhost)
02060 {
02061 dbg_return_if (rq == NULL, ~0);
02062
02063 rq->vhost = vhost;
02064
02065 return 0;
02066 }
02067