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
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 addr_t local_addr, peer_addr;
00052 int cgi;
00053 size_t idle_timeout;
00054 size_t post_timeout;
00055 size_t post_maxsize;
00056 vhost_t *vhost;
00057 size_t padding;
00058 };
00059
00060 typedef struct upload_info_s
00061 {
00062 char mime_type[MIME_TYPE_BUFSZ];
00063 char filename[U_FILENAME_MAX];
00064 size_t size;
00065 } upload_info_t;
00066
00067 enum {
00068 REQUEST_DEFAULT_IDLE_TIMEOUT = 10,
00069 REQUEST_DEFAULT_POST_TIMEOUT = 600,
00070 REQUEST_DEFAULT_POST_MAXSIZE = 5*1024000,
00071 };
00072
00073
00074 #define REQUEST_SET_STRING_FIELD(lval, rval) \
00075 do { \
00076 U_FREE(lval); \
00077 if(rval) \
00078 { \
00079 lval = u_strdup(rval); \
00080 dbg_err_if(lval == NULL); \
00081 } \
00082 } while(0)
00083
00084
00085 int request_is_encoding_accepted(request_t *rq, const char *encoding)
00086 {
00087 char *pp, *tok, *src, *buf = NULL;
00088 const char *accept_encoding;
00089 int rc = 0;
00090
00091 dbg_err_if (rq == NULL);
00092 dbg_err_if (encoding == NULL);
00093
00094 accept_encoding = header_get_field_value(rq->header, "Accept-Encoding");
00095 if(accept_encoding)
00096 {
00097
00098 buf = u_strdup(accept_encoding);
00099 dbg_err_if(buf == NULL);
00100
00101
00102 for(src = buf; (tok = strtok_r(src, " ,", &pp)) != NULL; src = NULL)
00103 {
00104 if(strcasecmp(tok, encoding) == 0)
00105 {
00106 rc++;
00107 break;
00108 }
00109 }
00110
00111 U_FREE(buf);
00112 }
00113
00114 return rc;
00115 err:
00116 U_FREE(buf);
00117 return 0;
00118 }
00119
00135 io_t *request_io(request_t *rq)
00136 {
00137 dbg_return_if (rq == NULL, NULL);
00138
00139 return rq->io;
00140 }
00141
00153 vars_t *request_get_cookies(request_t *rq)
00154 {
00155 dbg_return_if (rq == NULL, NULL);
00156
00157 return rq->cookies;
00158 }
00159
00171 const char *request_get_cookie(request_t *rq, const char *name)
00172 {
00173 var_t *v;
00174
00175 dbg_return_if (rq == NULL, NULL);
00176 dbg_return_if (name == NULL, NULL);
00177
00178 v = vars_get(rq->cookies, name);
00179
00180 return v ? var_get_value(v): NULL;
00181 }
00182
00193 vars_t *request_get_args(request_t *rq)
00194 {
00195 dbg_return_if (rq == NULL, NULL);
00196
00197 return rq->args;
00198 }
00199
00210 vars_t *request_get_getargs(request_t *rq)
00211 {
00212 dbg_return_if (rq == NULL, NULL);
00213
00214 return rq->args_get;
00215 }
00216
00227 vars_t *request_get_postargs(request_t *rq)
00228 {
00229 dbg_return_if (rq == NULL, NULL);
00230
00231 return rq->args_post;
00232 }
00233
00247 const char *request_get_arg(request_t *rq, const char *name)
00248 {
00249 var_t *v;
00250
00251 dbg_return_if (rq == NULL, NULL);
00252 dbg_return_if (name == NULL, NULL);
00253
00254 v = vars_get(rq->args, name);
00255
00256 return v ? var_get_value(v): NULL;
00257 }
00258
00272 const char *request_get_getarg(request_t *rq, const char *name)
00273 {
00274 var_t *v;
00275
00276 dbg_return_if (rq == NULL, NULL);
00277 dbg_return_if (name == NULL, NULL);
00278
00279 v = vars_get(rq->args_get, name);
00280
00281 return v ? var_get_value(v): NULL;
00282 }
00283
00297 const char *request_get_postarg(request_t *rq, const char *name)
00298 {
00299 var_t *v;
00300
00301 dbg_return_if (rq == NULL, NULL);
00302 dbg_return_if (name == NULL, NULL);
00303
00304 v = vars_get(rq->args_post, name);
00305
00306 return v ? var_get_value(v): NULL;
00307 }
00308
00309 int request_set_field(request_t *rq, const char *name, const char *value)
00310 {
00311 dbg_return_if (rq == NULL, ~0);
00312 dbg_return_if (name == NULL, ~0);
00313 dbg_return_if (value == NULL, ~0);
00314
00315 return header_set_field(rq->header, name, value);
00316 }
00317
00328 const char *request_get_uri(request_t *rq)
00329 {
00330 dbg_return_if (rq == NULL, NULL);
00331
00332 return rq->uri;
00333 }
00334
00345 const char *request_get_filename(request_t *rq)
00346 {
00347 dbg_return_if (rq == NULL, NULL);
00348
00349 return rq->filename;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 int request_set_filename(request_t *rq, const char *filename)
00364 {
00365 dbg_err_if (rq == NULL);
00366 dbg_err_if (filename == NULL);
00367
00368 REQUEST_SET_STRING_FIELD(rq->filename, filename);
00369
00370 return 0;
00371 err:
00372 return ~0;
00373 }
00374
00385 const char *request_get_query_string(request_t *rq)
00386 {
00387 dbg_return_if (rq == NULL, NULL);
00388
00389 return rq->query;
00390 }
00391
00402 const char *request_get_path_info(request_t *rq)
00403 {
00404 dbg_return_if (rq == NULL, NULL);
00405
00406 return rq->path_info;
00407 }
00408
00409
00410 static int request_parse_ims(request_t *rq)
00411 {
00412 const char *ims;
00413
00414 dbg_err_if (rq == NULL);
00415
00416 rq->if_modified_since = 0;
00417
00418 ims = header_get_field_value(rq->header, "If-Modified-Since");
00419 if(ims)
00420 dbg_err_if(u_httpdate_to_tt(ims, &rq->if_modified_since));
00421
00422 err:
00423 return 0;
00424 }
00425
00436 time_t request_get_if_modified_since(request_t *rq)
00437 {
00438 dbg_return_if (rq == NULL, (time_t) -1);
00439
00440 return rq->if_modified_since;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 int request_set_resolved_filename(request_t *rq, const char *resolved_fn)
00455 {
00456 dbg_err_if (rq == NULL);
00457 dbg_err_if (resolved_fn == NULL);
00458
00459 REQUEST_SET_STRING_FIELD(rq->resolved_filename, resolved_fn);
00460
00461 return 0;
00462 err:
00463 return ~0;
00464 }
00465
00476 http_t* request_get_http(request_t *rq)
00477 {
00478 dbg_return_if (rq == NULL, NULL);
00479
00480 return rq->http;
00481 }
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 int request_bind(request_t *rq, io_t *in)
00495 {
00496 dbg_return_if (rq == NULL, ~0);
00497 dbg_return_if (in == NULL, ~0);
00498
00499 rq->io = in;
00500
00501 return 0;
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 int request_set_query_string(request_t *rq, const char *query)
00516 {
00517 dbg_err_if (rq == NULL);
00518 dbg_err_if (query == NULL);
00519
00520 REQUEST_SET_STRING_FIELD(rq->query, query);
00521
00522 return 0;
00523 err:
00524 return ~0;
00525 }
00526
00527 void request_clear_uri(request_t *rq)
00528 {
00529 U_FREE(rq->uri);
00530 U_FREE(rq->protocol);
00531 U_FREE(rq->path_info);
00532 U_FREE(rq->query);
00533 U_FREE(rq->filename);
00534 U_FREE(rq->resolved_path_info);
00535 U_FREE(rq->resolved_filename);
00536 U_FREE(rq->content_type);
00537 U_FREE(rq->content_encoding);
00538 U_FREE(rq->cli_rq);
00539 }
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552 int request_set_path_info(request_t *rq, const char *path_info)
00553 {
00554 dbg_err_if (rq == NULL);
00555 dbg_err_if (path_info == NULL);
00556
00557 REQUEST_SET_STRING_FIELD(rq->path_info, path_info);
00558
00559 return 0;
00560 err:
00561 return ~0;
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575 int request_set_resolved_path_info(request_t *rq, const char *resolved_pi)
00576 {
00577 dbg_err_if (rq == NULL);
00578 dbg_err_if (resolved_pi == NULL);
00579
00580 REQUEST_SET_STRING_FIELD(rq->resolved_path_info, resolved_pi);
00581
00582 return 0;
00583 err:
00584 return ~0;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600 int request_set_uri(request_t *rq, const char *uri,
00601 int (*is_valid_uri)(void*, const char *, size_t),
00602 void* arg)
00603 {
00604 char *p, *fn, *pi;
00605 size_t uri_len = strlen(uri);
00606 char cp[4096];
00607
00608 dbg_err_if (rq == NULL);
00609 dbg_err_if (uri == NULL);
00610
00611
00612
00613 request_clear_uri(rq);
00614
00615
00616
00617 warn_err_ifm(uri_len >= sizeof(cp), "Request URI too long");
00618
00619 REQUEST_SET_STRING_FIELD(rq->uri, uri);
00620
00621
00622 if((p = strchr(uri, '?')) != NULL)
00623 dbg_err_if(request_set_query_string(rq, ++p));
00624
00625
00626 dbg_err_if(u_urlncpy(cp, rq->uri, uri_len, URLCPY_DECODE) <= 0);
00627
00628 if((p = strchr(cp, '?')) != NULL)
00629 *p++ = 0;
00630
00631
00632 dbg_err_if(u_uri_normalize(cp));
00633
00634
00635 dbg_err_if(request_set_filename(rq, cp));
00636
00637
00638 fn = cp;
00639 pi = fn + strlen(fn);
00640 for(;;)
00641 {
00642 if(is_valid_uri == NULL || is_valid_uri(arg, fn, pi - fn))
00643 {
00644 dbg_err_if(request_set_filename(rq, fn));
00645 rq->filename[pi-fn] = 0;
00646 if(strlen(pi))
00647 dbg_err_if(request_set_path_info(rq, pi));
00648 break;
00649 } else {
00650 if((p = u_strnrchr(fn, '/', pi - fn)) == NULL)
00651 break;
00652 pi = p;
00653 }
00654 }
00655
00656 return 0;
00657 err:
00658 return ~0;
00659 }
00660
00661 static int request_set_proto(request_t *rq, const char *proto)
00662 {
00663 dbg_err_if (rq == NULL);
00664 dbg_err_if (proto == NULL);
00665
00666
00667 if(strncasecmp(proto, "http", 4))
00668 return ~0;
00669
00670 REQUEST_SET_STRING_FIELD(rq->protocol, proto);
00671
00672 return 0;
00673 err:
00674 return ~0;
00675 }
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688 int request_set_client_request(request_t *rq, const char *ln)
00689 {
00690 char *p;
00691 dbg_err_if(rq == NULL);
00692 dbg_err_if(ln == NULL);
00693
00694 rq->cli_rq = u_strdup(ln);
00695 dbg_err_if(rq->cli_rq == NULL);
00696
00697
00698 for(p = rq->cli_rq; *p && (*p != '\r' && *p != '\n'); ++p)
00699 continue;
00700 *p = 0;
00701
00702 return 0;
00703 err:
00704 return ~0;
00705 }
00706
00717 const char *request_get_client_request(request_t *rq)
00718 {
00719 return rq->cli_rq;
00720 }
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730 int request_set_method(request_t *rq, const char *method)
00731 {
00732 dbg_return_if (rq == NULL, ~0);
00733 dbg_return_if (method == NULL, ~0);
00734
00735 if(!strcasecmp(method, "get"))
00736 rq->method = HM_GET;
00737 else if(!strcasecmp(method, "head"))
00738 rq->method = HM_HEAD;
00739 else if(!strcasecmp(method, "post"))
00740 rq->method = HM_POST;
00741 else {
00742
00743 rq->method = HM_UNKNOWN;
00744 return ~0;
00745 }
00746
00747 return 0;
00748 }
00749
00750 static int request_set_content_length(request_t *rq)
00751 {
00752 const char *clen;
00753 size_t len;
00754
00755 dbg_err_if (rq == NULL);
00756
00757 clen = header_get_field_value(rq->header, "Content-Length");
00758 dbg_err_if(clen == NULL || (len = atoi(clen)) < 0);
00759
00760 rq->content_length = len;
00761
00762 return 0;
00763 err:
00764 return ~0;
00765 }
00766
00767 static int request_parse_cookie(request_t *rq, field_t *field)
00768 {
00769 enum { BUFSZ = 4096 };
00770 char *pp, *tok, *src, buf[BUFSZ];
00771
00772 dbg_err_if (rq == NULL);
00773 dbg_err_if (field == NULL);
00774
00775 dbg_err_if(field_get_value(field) == NULL);
00776
00777
00778 strncpy(buf, field_get_value(field), BUFSZ);
00779
00780
00781 for(src = buf; (tok = strtok_r(src, " ;", &pp)) != NULL; src = NULL)
00782 dbg_if(vars_add_urlvar(rq->cookies, tok, NULL));
00783
00784 return 0;
00785 err:
00786 return ~0;
00787 }
00788
00789 static int request_parse_cookies(request_t *rq)
00790 {
00791 field_t *f;
00792 size_t i, count;
00793
00794 dbg_err_if (rq == NULL);
00795
00796 count = header_field_count(rq->header);
00797 for(i = 0; i < count; ++i)
00798 {
00799 f = header_get_fieldn(rq->header, i);
00800 dbg_err_if(f == NULL);
00801 if(strcasecmp(field_get_name(f), "cookie") == 0)
00802 dbg_err_if(request_parse_cookie(rq, f));
00803 }
00804
00805 return 0;
00806 err:
00807 return ~0;
00808 }
00809
00810
00811
00812 static int request_parse_query_args_from(request_t *rq, int offset,
00813 vars_t *vs)
00814 {
00815 char *pp, *tok, *src, *query = NULL;
00816 var_t *v;
00817
00818 dbg_err_if (rq == NULL);
00819
00820 if(!rq->query)
00821 return 0;
00822
00823
00824 query = u_strdup(rq->query + offset);
00825 dbg_err_if(query == NULL);
00826
00827
00828 for(src = query; (tok = strtok_r(src, "&", &pp)) != NULL; src = NULL)
00829 {
00830
00831 dbg_if(vars_add_urlvar(rq->args, tok, &v));
00832
00833
00834 if(vs)
00835 dbg_err_if(vars_add(vs, v));
00836 }
00837
00838 U_FREE(query);
00839
00840 return 0;
00841 err:
00842 U_FREE(query);
00843 return ~0;
00844 }
00845
00846 static int request_cb_add_post_var(void *arg, const char *tok)
00847 {
00848 request_t *rq = (request_t*)arg;
00849 var_t *v;
00850
00851 dbg_err_if(rq == NULL);
00852
00853
00854 dbg_if(vars_add_urlvar(rq->args, tok, &v));
00855
00856
00857 dbg_err_if(vars_add(rq->args_post, v));
00858
00859 return 0;
00860 err:
00861 return ~0;
00862 }
00863
00864 static int request_cb_add_get_var(void *arg, const char *tok)
00865 {
00866 request_t *rq = (request_t*)arg;
00867 var_t *v;
00868
00869 dbg_err_if(rq == NULL);
00870
00871
00872 dbg_if(vars_add_urlvar(rq->args, tok, &v));
00873
00874
00875 dbg_err_if(vars_add(rq->args_get, v));
00876
00877 return 0;
00878 err:
00879 return ~0;
00880 }
00881
00882 static int foreach_query_var(const char *urlquery, int offset,
00883 int(*cb)(void*,const char*), void *arg)
00884 {
00885 char *pp, *tok, *src, *query = NULL;
00886
00887 dbg_err_if(offset < 0);
00888 dbg_err_if(cb == NULL);
00889
00890 if(!urlquery)
00891 return 0;
00892
00893
00894 query = u_strdup(urlquery + offset);
00895 dbg_err_if(query == NULL);
00896
00897
00898 for(src = query; (tok = strtok_r(src, "&", &pp)) != NULL; src = NULL)
00899 {
00900
00901 dbg_err_if(cb(arg, tok));
00902 }
00903
00904 U_FREE(query);
00905
00906 return 0;
00907 err:
00908 U_FREE(query);
00909 return ~0;
00910 }
00911
00912 static int request_parse_query_args(request_t *rq)
00913 {
00914 dbg_err_if(rq == NULL);
00915
00916 return foreach_query_var(rq->query, 0, request_cb_add_get_var, (void*)rq);
00917 err:
00918 return ~0;
00919 }
00920
00921
00922 void request_set_cgi(request_t *rq, int cgi)
00923 {
00924 rq->cgi = cgi;
00925 return;
00926 }
00927
00939 ssize_t request_get_content_length(request_t *rq)
00940 {
00941 dbg_return_if (rq == NULL, -1);
00942
00943 return (ssize_t) rq->content_length;
00944 }
00945
00946 static int match_content_type(header_t *h, const char *mime_type)
00947 {
00948 const char *ct;
00949
00950 dbg_return_if (h == NULL, 0);
00951 dbg_return_if (mime_type == NULL, 0);
00952
00953 ct = header_get_field_value(h, "Content-Type");
00954 if(ct == NULL || strncasecmp(ct, mime_type, strlen(mime_type)))
00955 return 0;
00956
00957 return 1;
00958 }
00959
00960 static int request_is_multipart_formdata(request_t *rq)
00961 {
00962 return match_content_type(rq->header, "multipart/form-data");
00963 }
00964
00965 static int request_parse_urlencoded_data(request_t *rq)
00966 {
00967 ssize_t qsz, len;
00968
00969 dbg_err_if (rq == NULL);
00970
00971 len = rq->content_length;
00972
00973 qsz = (rq->query ? strlen(rq->query) : 0);
00974
00975
00976 rq->query = u_realloc(rq->query, len + qsz + 2);
00977 dbg_err_if(rq->query == NULL);
00978
00979
00980
00981 rq->query[qsz] = 0;
00982 if(qsz)
00983 {
00984 strcat(rq->query, "&");
00985 ++qsz;
00986 }
00987
00988
00989 dbg_err_if(io_read(rq->io, rq->query + qsz, len) != len);
00990
00991
00992 rq->query[qsz + len] = 0;
00993
00994
00995 dbg_err_if(foreach_query_var(rq->query, qsz,
00996 request_cb_add_post_var, (void*)rq));
00997
00998 return 0;
00999 err:
01000 return ~0;
01001 }
01002
01003
01004
01005 static int request_get_fieldparam(request_t *rq, const char *field_name,
01006 const char *param_name, char *buf, size_t size)
01007 {
01008 const char *param_value, *field_value, *p;
01009 size_t pv_len;
01010
01011 dbg_err_if (rq == NULL);
01012 dbg_err_if (field_name == NULL);
01013 dbg_err_if (param_name == NULL);
01014 dbg_err_if (buf == NULL);
01015 dbg_err_if (size == 0);
01016
01017 field_value = header_get_field_value(rq->header, field_name);
01018 dbg_err_if(field_value == NULL);
01019
01020
01021 param_value = u_stristr(field_value, param_name);
01022 dbg_err_if(param_value == NULL);
01023
01024
01025 param_value += strlen(param_name);
01026
01027
01028 dbg_err_if(*param_value++ != '=');
01029
01030
01031 for(p = param_value; ;++p)
01032 if(*p == '\0' || *p == ';' || isspace(*p))
01033 break;
01034
01035
01036 pv_len = p - param_value;
01037
01038
01039 dbg_err_if(pv_len > size - 1);
01040
01041
01042 strncpy(buf, param_value, pv_len);
01043 buf[MIN(pv_len, size - 1)] = 0;
01044
01045 return 0;
01046 err:
01047 return ~0;
01048 }
01049
01050 static int is_multipart_mixed(header_t *h)
01051 {
01052 return match_content_type(h, "multipart/mixed");
01053 }
01054
01055 static int is_encoded(header_t *h)
01056 {
01057 const char *cte;
01058
01059 dbg_return_if (h == NULL, 0);
01060
01061 if((cte = header_get_field_value(h, "Content-Transfer-Encoding")) == NULL)
01062 return 0;
01063
01064 if(strcasecmp(cte, "binary") == 0)
01065 return 0;
01066
01067 return 1;
01068 }
01069
01070 static inline int is_nl(char c)
01071 {
01072 return (c == '\n' || c == '\r' ? c : 0);
01073 }
01074
01075 static inline int is_quote(char c)
01076 {
01077 return (c == '"' || c == '\'' ? c : 0);
01078 }
01079
01080 static int parse_content_disposition(header_t *h, char *name, char *filename,
01081 size_t prmsz)
01082 {
01083 enum { BUFSZ = 512 };
01084 char *pp, *tok, *src, buf[BUFSZ];
01085 size_t n_len, fn_len;
01086 const char *cd;
01087 int q;
01088
01089 dbg_err_if (h == NULL);
01090 dbg_err_if (name == NULL);
01091 dbg_err_if (filename == NULL);
01092 dbg_err_if (prmsz == 0);
01093
01094 cd = header_get_field_value(h, "Content-Disposition");
01095 dbg_err_if(cd == NULL);
01096
01097 dbg_err_if(strlen(cd) >= BUFSZ);
01098
01099
01100 dbg_err_if(strncmp(cd, "form-data", strlen("form-data")));
01101
01102 name[0] = filename[0] = 0;
01103
01104
01105 strncpy(buf, cd, BUFSZ);
01106
01107
01108 n_len = strlen("name=");
01109 fn_len = strlen("filename=");
01110
01111
01112 for(src = buf; (tok = strtok_r(src, ";", &pp)) != NULL; src = NULL)
01113 {
01114
01115 while(isspace(*tok))
01116 ++tok;
01117
01118 if(strncmp(tok, "form-data", strlen("form-data")) == 0)
01119 continue;
01120 else if(strncmp(tok, "name=", n_len) == 0) {
01121
01122 tok += n_len;
01123
01124
01125 if((q = is_quote(tok[0])) != 0)
01126 ++tok;
01127 if(strlen(tok) && tok[strlen(tok) - 1] == q)
01128 tok[strlen(tok) - 1] = 0;
01129
01130 strncpy(name, tok, prmsz);
01131 } else if(strncmp(tok, "filename=", fn_len) == 0) {
01132
01133 tok += fn_len;
01134
01135
01136 if((q = is_quote(tok[0])) != 0)
01137 ++tok;
01138 if(strlen(tok) && tok[strlen(tok) - 1] == q)
01139 tok[strlen(tok) - 1] = 0;
01140
01141 strncpy(filename, tok, prmsz);
01142 }
01143
01144 }
01145
01146 return 0;
01147 err:
01148 return ~0;
01149 }
01150
01151
01152
01153
01154
01155
01156
01157
01158 static ssize_t read_until(io_t *io, const char *stop_at, char *obuf,
01159 size_t size, int *found)
01160 {
01161
01162
01163
01164 #define SETUP_BUF_ACCESS_AT(idx) \
01165 if(idx >= wtot) { \
01166 if(idx >= size) \
01167 return wtot; \
01168 \
01169 \
01170 dbg_err_if((rc = io_read(io, wbuf, idx + 1 - wtot)) < 0); \
01171 if(rc == 0 || rc < idx + 1 - wtot) \
01172 return wtot + rc; \
01173 wbuf += rc; \
01174 wtot += rc; \
01175 }
01176
01177 int sa_len = strlen(stop_at);
01178 int i, t, shift[256], rc;
01179 unsigned char c;
01180 size_t wtot = 0;
01181 char *wbuf = obuf;
01182
01183 dbg_err_if (io == NULL);
01184 dbg_err_if (stop_at == NULL);
01185 dbg_err_if (obuf == NULL);
01186
01187 dbg_err_if (found == NULL);
01188
01189 for(i = 0; i < 256; ++i)
01190 shift[i] = sa_len;
01191
01192 for(i = 0; i < sa_len; ++i)
01193 shift[ stop_at[i] ] = sa_len - i - 1;
01194
01195 *found = 0;
01196
01197 for(i = t = sa_len-1; t >= 0; --i, --t)
01198 {
01199 SETUP_BUF_ACCESS_AT(i);
01200
01201 while((c = obuf[i]) != stop_at[t])
01202 {
01203 i += MAX(sa_len - t, shift[c]);
01204
01205 SETUP_BUF_ACCESS_AT(i);
01206
01207 t = sa_len - 1;
01208 }
01209 }
01210
01211 *found = 1;
01212
01213
01214 return wtot;
01215 err:
01216 return -1;
01217 }
01218
01219
01238 vars_t *request_get_uploads(request_t *rq)
01239 {
01240 return rq->uploads;
01241 }
01242
01243
01244
01245
01246
01247
01248
01249
01250 static int request_add_uploaded_file(request_t *rq, const char *name,
01251 const char *filename, const char *tmp_filename, const char *mime_type)
01252 {
01253 struct stat st;
01254 var_t *v = NULL;
01255 upload_info_t *info = NULL;
01256
01257 dbg_err_if (rq == NULL);
01258 dbg_err_if (name == NULL);
01259
01260 dbg_err_if (tmp_filename == NULL);
01261
01262
01263 dbg_err_sif (stat(tmp_filename, &st) < 0);
01264
01265
01266 dbg_err_if(var_create(name, tmp_filename, &v));
01267
01268
01269 dbg_err_if((info = u_zalloc(sizeof(upload_info_t))) == NULL);
01270
01271
01272 info->size = st.st_size;
01273 if(mime_type)
01274 snprintf(info->mime_type, MIME_TYPE_BUFSZ, "%s", mime_type);
01275 else
01276 info->mime_type[0] = 0;
01277
01278 if(filename)
01279 snprintf(info->filename, U_FILENAME_MAX, "%s", filename);
01280
01281
01282 var_set_opaque(v, info);
01283 info = NULL;
01284
01285
01286 dbg_err_if(vars_add(rq->uploads, v));
01287
01288 return 0;
01289 err:
01290 if(info)
01291 U_FREE(info);
01292 if(v)
01293 var_free(v);
01294 return ~0;
01295 }
01296
01297 static int request_get_uploaded_filev(request_t *rq, var_t *v,
01298 char local_filename[U_FILENAME_MAX], char client_filename[U_FILENAME_MAX],
01299 char mime_type[MIME_TYPE_BUFSZ], size_t *file_size)
01300 {
01301 upload_info_t *info;
01302 const char *tmp_fqn;
01303
01304 dbg_err_if (rq == NULL);
01305 dbg_err_if (v == NULL);
01306 dbg_err_if (local_filename == NULL);
01307 dbg_err_if (client_filename == NULL);
01308 dbg_err_if (mime_type == NULL);
01309 dbg_err_if (file_size == NULL);
01310
01311 info = var_get_opaque(v);
01312 dbg_err_if(info == NULL);
01313
01314 tmp_fqn = var_get_value(v);
01315 dbg_err_if(tmp_fqn == NULL);
01316
01317
01318 strncpy(local_filename, tmp_fqn, U_FILENAME_MAX);
01319 strncpy(mime_type, info->mime_type, MIME_TYPE_BUFSZ);
01320 strncpy(client_filename, info->filename, U_FILENAME_MAX);
01321 *file_size = info->size;
01322
01323 return 0;
01324 err:
01325 return ~0;
01326 }
01327
01350 int request_get_uploaded_file(request_t *rq, const char *name, size_t idx,
01351 char local_filename[U_FILENAME_MAX], char client_filename[U_FILENAME_MAX],
01352 char mime_type[MIME_TYPE_BUFSZ], size_t *file_size)
01353 {
01354 var_t *v;
01355
01356 dbg_err_if (rq == NULL);
01357 dbg_err_if (name == NULL);
01358 dbg_err_if (idx >= vars_count(rq->uploads));
01359 dbg_err_if (local_filename == NULL);
01360 dbg_err_if (client_filename == NULL);
01361 dbg_err_if (mime_type == NULL);
01362 dbg_err_if (file_size == NULL);
01363
01364 v = vars_geti(rq->uploads, name, idx);
01365 dbg_err_if(v == NULL);
01366
01367 return request_get_uploaded_filev(rq, v, local_filename, client_filename,
01368 mime_type, file_size);
01369 err:
01370 return ~0;
01371 }
01372
01373 static int request_parse_multipart_chunk(request_t *rq, io_t *io,
01374 const char *boundary, int *eof)
01375 {
01376 enum { PRMSZ = 512, BUFSZ = 4096 };
01377 header_t *h = NULL;
01378 io_t *tmpio = NULL;
01379 var_t *v = NULL;
01380 char name[PRMSZ], filename[PRMSZ], buf[BUFSZ];
01381 size_t bound_len;
01382 int found;
01383 ssize_t rc;
01384
01385
01386 dbg_err_if(header_create(&h));
01387
01388
01389 dbg_err_if(header_load(h, io));
01390
01391 warn_err_ifm(is_multipart_mixed(h),
01392 "multipart/mixed content is not supported yet");
01393
01394
01395 warn_err_ifm(is_encoded(h),
01396 "encoded file upload is not supported");
01397
01398 dbg_err_if(parse_content_disposition(h, name, filename, PRMSZ));
01399
01400
01401 bound_len = strlen(boundary);
01402
01403 if(filename[0] != '\0')
01404 {
01405 dbg_err_if(BUFSZ <= bound_len);
01406
01407
01408 dbg_err_if(u_tmpfile_open(&tmpio));
01409
01410 for(found = 0; !found; )
01411 {
01412 rc = read_until(io, boundary, buf, BUFSZ, &found);
01413 dbg_err_if(rc <= 0);
01414
01415
01416 if(found)
01417 {
01418 rc -= (bound_len + 2);
01419 dbg_err_if(rc < 0);
01420 }
01421
01422
01423 dbg_err_if(io_write(tmpio, buf, rc) < 0);
01424 }
01425
01426
01427 dbg_err_if(io_name_get(tmpio, buf, BUFSZ));
01428
01429
01430 io_free(tmpio); tmpio = NULL;
01431
01432
01433 dbg_err_if(request_add_uploaded_file(rq, name, filename, buf,
01434 header_get_field_value(h, "Content-Type")));
01435
01436
01437 dbg_err_if(io_gets(io, buf, BUFSZ) <= 0);
01438
01439 if(strncmp(buf, "--", 2) == 0)
01440 *eof = 1;
01441
01442 } else {
01443
01444 rc = read_until(io, boundary, buf, BUFSZ, &found);
01445 dbg_err_if(rc <= 0);
01446
01447
01448 warn_err_ifm(!found, "malformed request or BUFSZ too small");
01449
01450 rc -= (bound_len + 2);
01451 dbg_err_if(rc < 0);
01452
01453
01454 buf[rc] = 0;
01455
01456
01457 dbg_err_if(var_bin_create(name, buf, rc, &v));
01458 dbg_if(vars_add(rq->args, v));
01459
01460
01461 dbg_if(vars_add(rq->args_post, v));
01462
01463
01464 dbg_err_if(io_gets(io, buf, BUFSZ) <= 0);
01465
01466 if(strncmp(buf, "--", 2) == 0)
01467 *eof = 1;
01468 }
01469
01470 header_free(h);
01471
01472 return 0;
01473 err:
01474 if(tmpio)
01475 io_free(tmpio);
01476 if(h)
01477 header_free(h);
01478 return ~0;
01479 }
01480
01481 static int request_parse_multipart_data(request_t *rq)
01482 {
01483 enum { BOUNDARY_BUFSZ = 128, BUFSZ = 1024 };
01484 char boundary[BOUNDARY_BUFSZ], buf[BUFSZ];
01485 int eof;
01486
01487
01488 strcpy(boundary, "--");
01489
01490 dbg_err_if(request_get_fieldparam(rq, "Content-Type", "boundary",
01491 boundary + 2, BOUNDARY_BUFSZ - 2));
01492
01493 dbg_err_if(strlen(boundary) == 0);
01494
01495
01496 for(;;)
01497 {
01498 dbg_err_if(io_gets(rq->io, buf, BUFSZ) <= 0);
01499 if(!strncmp(buf, boundary, strlen(boundary)))
01500 break;
01501 }
01502
01503
01504 for(eof = 0; eof == 0; )
01505 dbg_err_if(request_parse_multipart_chunk(rq, rq->io, boundary, &eof));
01506
01507 return 0;
01508 err:
01509 return ~0;
01510 }
01511
01512 static int request_cb_close_socket(talarm_t *al, void *arg)
01513 {
01514 io_t *io = (io_t*)arg;
01515
01516 u_unused_args(al);
01517
01518 warn("[%x] connection timed out, closing", io);
01519
01520
01521 io_close(io);
01522
01523 return 0;
01524 }
01525
01526 int request_parse_data(request_t *rq)
01527 {
01528 talarm_t *al = NULL;
01529 int rc = HTTP_STATUS_BAD_REQUEST;
01530
01531 if(rq->method == HM_POST)
01532 {
01533
01534 dbg_err_if(timerm_add(rq->post_timeout, request_cb_close_socket,
01535 (void*)rq->io, &al));
01536
01537
01538 dbg_err_if(request_set_content_length(rq) &&
01539 (rc = HTTP_STATUS_LENGTH_REQUIRED));
01540
01541 if(rq->content_length == 0)
01542 return 0;
01543
01544
01545 dbg_err_if(rq->content_length > rq->post_maxsize &&
01546 (rc = HTTP_STATUS_REQUEST_TOO_LARGE));
01547
01548
01549 dbg_err_if(request_parse_query_args(rq));
01550
01551 if(request_is_multipart_formdata(rq))
01552 {
01553
01554 dbg_err_if(request_parse_multipart_data(rq));
01555 } else {
01556
01557 dbg_err_if(request_parse_urlencoded_data(rq));
01558 }
01559
01560
01561 dbg_if(timerm_del(al)); al = NULL;
01562 } else {
01563
01564 dbg_err_if(request_parse_query_args(rq));
01565 }
01566
01567 return 0;
01568 err:
01569 return rc;
01570 }
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581 int request_parse_header(request_t *rq,
01582 int (*is_valid_uri)(void*, const char *, size_t),
01583 void* arg)
01584 {
01585 enum { BUFSZ = 4096 };
01586 const char WP[] = " \t\r\n";
01587 char ln[BUFSZ], *pp, *method, *uri, *proto;
01588 talarm_t *al = NULL;
01589
01590 dbg_err_if (rq == NULL);
01591 dbg_err_if (rq->io == NULL);
01592
01593
01594 dbg_err_if(timerm_add(rq->idle_timeout, request_cb_close_socket,
01595 (void*)rq->io, &al));
01596
01597 if(!rq->cgi)
01598 {
01599
01600 dbg_err_if(io_gets(rq->io, ln, BUFSZ) <= 0);
01601
01602
01603 dbg_err_if(request_set_client_request(rq, ln));
01604
01605 method = strtok_r(ln, WP, &pp);
01606 dbg_err_if(!method || request_set_method(rq, method));
01607
01608 uri = strtok_r(NULL, WP, &pp);
01609 dbg_err_if(!uri || request_set_uri(rq, uri, is_valid_uri, arg));
01610
01611
01612 proto = strtok_r(NULL, WP, &pp);
01613 dbg_err_if(!proto || request_set_proto(rq, proto));
01614
01615 dbg_err_if(header_load(rq->header, rq->io));
01616 } else {
01617 dbg_err_if(header_load_from_cgienv(rq->header));
01618 }
01619
01620
01621 dbg_err_if(request_parse_ims(rq));
01622
01623
01624 dbg_err_if(request_parse_cookies(rq));
01625
01626
01627 if(request_get_method(rq) == HM_POST)
01628 dbg_err_if(request_set_content_length(rq));
01629
01630
01631 dbg_if(timerm_del(al)); al = NULL;
01632
01633 return 0;
01634 err:
01635 if(al)
01636 timerm_del(al);
01637 return ~0;
01638 }
01639
01651 int request_get_method(request_t *rq)
01652 {
01653 dbg_return_if (rq == NULL, HM_UNKNOWN);
01654
01655 return rq->method;
01656 }
01657
01669 const char* request_get_protocol(request_t *rq)
01670 {
01671 dbg_return_if (rq == NULL, "unknown");
01672
01673 return rq->protocol;
01674 }
01675
01686 const char *request_get_resolved_filename(request_t *rq)
01687 {
01688 dbg_return_if (rq == NULL, NULL);
01689
01690 return rq->resolved_filename;
01691 }
01692
01703 const char *request_get_resolved_path_info(request_t *rq)
01704 {
01705 dbg_return_if (rq == NULL, NULL);
01706
01707 return rq->resolved_path_info;
01708 }
01709
01710 int request_print(request_t *rq)
01711 {
01712 dbg_return_if (rq == NULL, ~0);
01713
01714 dbg("method: %u", rq->method);
01715 dbg("uri: %s", rq->uri);
01716 dbg("proto: %s", rq->protocol);
01717 dbg("filename: %s", rq->filename);
01718 dbg("resolved filename: %s", rq->resolved_filename);
01719 dbg("path_info: %s", rq->path_info);
01720 dbg("resolved path_info: %s", rq->resolved_path_info);
01721 dbg("query: %s", rq->query);
01722
01723 return 0;
01724 }
01725
01726 static int request_load_config(request_t *rq)
01727 {
01728 u_config_t *c;
01729 const char *v;
01730
01731 dbg_err_if (rq == NULL);
01732 dbg_err_if (rq->http == NULL);
01733 dbg_err_if (http_get_config(rq->http) == NULL);
01734
01735 c = http_get_config(rq->http);
01736
01737
01738 rq->idle_timeout = REQUEST_DEFAULT_IDLE_TIMEOUT;
01739 rq->post_timeout = REQUEST_DEFAULT_POST_TIMEOUT;
01740 rq->post_maxsize = REQUEST_DEFAULT_POST_MAXSIZE;
01741
01742
01743 if((v = u_config_get_subkey_value(c, "idle_timeout")) != NULL)
01744 rq->idle_timeout = MAX(1, atoi(v));
01745
01746
01747 if((v = u_config_get_subkey_value(c, "post_timeout")) != NULL)
01748 rq->post_timeout = MAX(5, atoi(v));
01749
01750
01751 if((v = u_config_get_subkey_value(c, "post_maxsize")) != NULL)
01752 rq->post_maxsize = MAX(1024, atoi(v));
01753
01754 return 0;
01755 err:
01756 return ~0;
01757 }
01758
01759 int request_create(http_t *http, request_t **prq)
01760 {
01761 request_t *rq = NULL;
01762
01763 dbg_return_if (prq == NULL, ~0);
01764 dbg_return_if (http == NULL, ~0);
01765
01766 rq = u_zalloc(sizeof(request_t));
01767 dbg_err_if(rq == NULL);
01768
01769 dbg_err_if(header_create(&rq->header));
01770
01771 dbg_err_if(vars_create(&rq->args));
01772 dbg_err_if(vars_create(&rq->cookies));
01773 dbg_err_if(vars_create(&rq->uploads));
01774
01775 dbg_err_if(vars_create(&rq->args_get));
01776 dbg_err_if(vars_create(&rq->args_post));
01777
01778
01779 dbg_err_if(vars_set_flags(rq->args_get, VARS_FLAG_FOREIGN));
01780 dbg_err_if(vars_set_flags(rq->args_post, VARS_FLAG_FOREIGN));
01781
01782 rq->http = http;
01783
01784 dbg_err_if(request_load_config(rq));
01785
01786 *prq = rq;
01787
01788 return 0;
01789 err:
01790 if(rq)
01791 request_free(rq);
01792 return ~0;
01793 }
01794
01795 static int request_unlink_uploads(var_t *v, void * arg)
01796 {
01797 dbg_err_if (v == NULL);
01798
01799 u_unused_args(arg);
01800
01801 if(var_get_opaque(v) && var_get_value(v))
01802 {
01803 u_remove(var_get_value(v));
01804 }
01805
01806 err:
01807 return 0;
01808 }
01809
01810 int request_free(request_t *rq)
01811 {
01812 if (rq)
01813 {
01814
01815 request_clear_uri(rq);
01816
01817 if(rq->header)
01818 header_free(rq->header);
01819
01820 if(rq->io)
01821 io_free(rq->io);
01822
01823 if(rq->uploads)
01824 {
01825
01826 vars_foreach(rq->uploads, request_unlink_uploads, NULL);
01827 vars_free(rq->uploads);
01828 }
01829
01830 if(rq->cookies)
01831 vars_free(rq->cookies);
01832
01833 if(rq->args_get)
01834 vars_free(rq->args_get);
01835
01836 if(rq->args_post)
01837 vars_free(rq->args_post);
01838
01839 if(rq->args)
01840 vars_free(rq->args);
01841
01842 U_FREE(rq);
01843 }
01844
01845 return 0;
01846 }
01847
01848
01849 int request_set_addr(request_t *rq, addr_t *addr)
01850 {
01851 dbg_return_if (rq == NULL, ~0);
01852 dbg_return_if (addr == NULL, ~0);
01853
01854 memcpy(&rq->local_addr, addr, sizeof(addr_t));
01855
01856 return 0;
01857 }
01858
01859
01860 int request_set_peer_addr(request_t *rq, addr_t *addr)
01861 {
01862 dbg_return_if (rq == NULL, ~0);
01863 dbg_return_if (addr == NULL, ~0);
01864
01865 memcpy(&rq->peer_addr, addr, sizeof(addr_t));
01866
01867 return 0;
01868 }
01869
01880 addr_t* request_get_addr(request_t *rq)
01881 {
01882 dbg_return_if (rq == NULL, NULL);
01883
01884 return &rq->local_addr;
01885 }
01886
01897 addr_t* request_get_peer_addr(request_t *rq)
01898 {
01899 dbg_return_if (rq == NULL, NULL);
01900
01901 return &rq->peer_addr;
01902 }
01903
01915 header_t* request_get_header(request_t *rq)
01916 {
01917 dbg_return_if (rq == NULL, NULL);
01918
01919 return rq->header;
01920 }
01921
01933 field_t* request_get_field(request_t *rq, const char *name)
01934 {
01935 dbg_return_if (rq == NULL, NULL);
01936 dbg_return_if (name == NULL, NULL);
01937
01938 return header_get_field(rq->header, name);
01939 }
01940
01952 const char* request_get_field_value(request_t *rq, const char *name)
01953 {
01954 dbg_return_if (rq == NULL, NULL);
01955 dbg_return_if (name == NULL, NULL);
01956
01957 return header_get_field_value(rq->header, name);
01958 }
01959
01960 vhost_t* request_get_vhost(request_t *rq)
01961 {
01962 dbg_return_if (rq == NULL, NULL);
01963
01964 return rq->vhost;
01965 }
01966
01967 int request_set_vhost(request_t *rq, vhost_t *vhost)
01968 {
01969 dbg_return_if (rq == NULL, ~0);
01970
01971 rq->vhost = vhost;
01972
01973 return 0;
01974 }
01975