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