00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "klone_conf.h"
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <ctype.h>
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <u/libu.h>
00018 #include <klone/request.h>
00019 #include <klone/utils.h>
00020 #include <klone/io.h>
00021 #include <klone/ioprv.h>
00022 #include <klone/http.h>
00023 #include <klone/addr.h>
00024 #include <klone/vars.h>
00025 #include <klone/timer.h>
00026
00027 struct request_s
00028 {
00029 http_t *http;
00030 header_t *header;
00031 io_t *io;
00032 int method;
00033 char *uri;
00034 char *protocol;
00035 char *path_info;
00036 char *query;
00037 char *filename;
00038 char *host;
00039 char *resolved_path_info;
00040 char *resolved_filename;
00041 vars_t *args;
00042 vars_t *cookies;
00043 vars_t *uploads;
00044 char *content_type;
00045 char *content_encoding;
00046 size_t content_length;
00047 time_t if_modified_since;
00048 addr_t local_addr, peer_addr;
00049 int cgi;
00050 size_t idle_timeout;
00051 size_t post_timeout;
00052 size_t post_maxsize;
00053 };
00054
00055 typedef struct upload_info_s
00056 {
00057 char mime_type[MIME_TYPE_BUFSZ];
00058 char filename[U_FILENAME_MAX];
00059 size_t size;
00060 } upload_info_t;
00061
00062 enum {
00063 REQUEST_DEFAULT_IDLE_TIMEOUT = 10,
00064 REQUEST_DEFAULT_POST_TIMEOUT = 600,
00065 REQUEST_DEFAULT_POST_MAXSIZE = 5*1024000,
00066 };
00067
00068
00069 #define REQUEST_SET_STRING_FIELD(lval, rval) \
00070 do { \
00071 U_FREE(lval); \
00072 if(rval) \
00073 { \
00074 lval = u_strdup(rval); \
00075 dbg_err_if(lval == NULL); \
00076 } \
00077 } while(0)
00078
00092 int request_is_encoding_accepted(request_t *rq, const char *encoding)
00093 {
00094 char *pp, *tok, *src, *buf = NULL;
00095 const char *accept_encoding;
00096 int rc = 0;
00097
00098 dbg_err_if (rq == NULL);
00099 dbg_err_if (encoding == NULL);
00100
00101 accept_encoding = header_get_field_value(rq->header, "Accept-Encoding");
00102 if(accept_encoding)
00103 {
00104
00105 buf = u_strdup(accept_encoding);
00106 dbg_err_if(buf == NULL);
00107
00108
00109 for(src = buf; (tok = strtok_r(src, " ,", &pp)) != NULL; src = NULL)
00110 {
00111 if(strcasecmp(tok, encoding) == 0)
00112 {
00113 rc++;
00114 break;
00115 }
00116 }
00117
00118 U_FREE(buf);
00119 }
00120
00121 return rc;
00122 err:
00123 U_FREE(buf);
00124 return 0;
00125 }
00126
00141 io_t *request_io(request_t *rq)
00142 {
00143 dbg_return_if (rq == NULL, NULL);
00144
00145 return rq->io;
00146 }
00147
00158 vars_t *request_get_cookies(request_t *rq)
00159 {
00160 dbg_return_if (rq == NULL, NULL);
00161
00162 return rq->cookies;
00163 }
00164
00175 const char *request_get_cookie(request_t *rq, const char *name)
00176 {
00177 var_t *v;
00178
00179 dbg_return_if (rq == NULL, NULL);
00180 dbg_return_if (name == NULL, NULL);
00181
00182 v = vars_get(rq->cookies, name);
00183
00184 return v ? var_get_value(v): NULL;
00185 }
00186
00196 vars_t *request_get_args(request_t *rq)
00197 {
00198 dbg_return_if (rq == NULL, NULL);
00199
00200 return rq->args;
00201 }
00202
00215 const char *request_get_arg(request_t *rq, const char *name)
00216 {
00217 var_t *v;
00218
00219 dbg_return_if (rq == NULL, NULL);
00220 dbg_return_if (name == NULL, NULL);
00221
00222 v = vars_get(rq->args, name);
00223
00224 return v ? var_get_value(v): NULL;
00225 }
00226
00238 int request_set_field(request_t *rq, const char *name, const char *value)
00239 {
00240 dbg_return_if (rq == NULL, ~0);
00241 dbg_return_if (name == NULL, ~0);
00242 dbg_return_if (value == NULL, ~0);
00243
00244 return header_set_field(rq->header, name, value);
00245 }
00246
00256 const char *request_get_uri(request_t *rq)
00257 {
00258 dbg_return_if (rq == NULL, NULL);
00259
00260 return rq->uri;
00261 }
00262
00272 const char *request_get_filename(request_t *rq)
00273 {
00274 dbg_return_if (rq == NULL, NULL);
00275
00276 return rq->filename;
00277 }
00278
00289 int request_set_filename(request_t *rq, const char *filename)
00290 {
00291 dbg_err_if (rq == NULL);
00292 dbg_err_if (filename == NULL);
00293
00294 REQUEST_SET_STRING_FIELD(rq->filename, filename);
00295
00296 return 0;
00297 err:
00298 return ~0;
00299 }
00300
00310 const char *request_get_query_string(request_t *rq)
00311 {
00312 dbg_return_if (rq == NULL, NULL);
00313
00314 return rq->query;
00315 }
00316
00326 const char *request_get_path_info(request_t *rq)
00327 {
00328 dbg_return_if (rq == NULL, NULL);
00329
00330 return rq->path_info;
00331 }
00332
00333
00334 static int request_parse_ims(request_t *rq)
00335 {
00336 const char *ims;
00337
00338 dbg_err_if (rq == NULL);
00339
00340 rq->if_modified_since = 0;
00341
00342 ims = header_get_field_value(rq->header, "If-Modified-Since");
00343 if(ims)
00344 dbg_err_if(u_httpdate_to_tt(ims, &rq->if_modified_since));
00345
00346 err:
00347 return 0;
00348 }
00349
00359 time_t request_get_if_modified_since(request_t *rq)
00360 {
00361 dbg_return_if (rq == NULL, (time_t) -1);
00362
00363 return rq->if_modified_since;
00364 }
00365
00376 int request_set_resolved_filename(request_t *rq, const char *resolved_fn)
00377 {
00378 dbg_err_if (rq == NULL);
00379 dbg_err_if (resolved_fn == NULL);
00380
00381 REQUEST_SET_STRING_FIELD(rq->resolved_filename, resolved_fn);
00382
00383 return 0;
00384 err:
00385 return ~0;
00386 }
00387
00397 http_t* request_get_http(request_t *rq)
00398 {
00399 dbg_return_if (rq == NULL, NULL);
00400
00401 return rq->http;
00402 }
00403
00414 int request_bind(request_t *rq, io_t *in)
00415 {
00416 dbg_return_if (rq == NULL, ~0);
00417 dbg_return_if (in == NULL, ~0);
00418
00419 rq->io = in;
00420
00421 return 0;
00422 }
00423
00434 int request_set_query_string(request_t *rq, const char *query)
00435 {
00436 dbg_err_if (rq == NULL);
00437 dbg_err_if (query == NULL);
00438
00439 REQUEST_SET_STRING_FIELD(rq->query, query);
00440
00441 return 0;
00442 err:
00443 return ~0;
00444 }
00445
00455 void request_clear_uri(request_t *rq)
00456 {
00457 U_FREE(rq->uri);
00458 U_FREE(rq->protocol);
00459 U_FREE(rq->path_info);
00460 U_FREE(rq->query);
00461 U_FREE(rq->filename);
00462 U_FREE(rq->host);
00463 U_FREE(rq->resolved_path_info);
00464 U_FREE(rq->resolved_filename);
00465 U_FREE(rq->content_type);
00466 U_FREE(rq->content_encoding);
00467 }
00468
00479 int request_set_path_info(request_t *rq, const char *path_info)
00480 {
00481 dbg_err_if (rq == NULL);
00482 dbg_err_if (path_info == NULL);
00483
00484 REQUEST_SET_STRING_FIELD(rq->path_info, path_info);
00485
00486 return 0;
00487 err:
00488 return ~0;
00489 }
00490
00501 int request_set_resolved_path_info(request_t *rq, const char *resolved_pi)
00502 {
00503 dbg_err_if (rq == NULL);
00504 dbg_err_if (resolved_pi == NULL);
00505
00506 REQUEST_SET_STRING_FIELD(rq->resolved_path_info, resolved_pi);
00507
00508 return 0;
00509 err:
00510 return ~0;
00511 }
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525 int request_set_uri(request_t *rq, const char *uri,
00526 int (*is_valid_uri)(void*, const char *, size_t),
00527 void* arg)
00528 {
00529 enum { REQUEST_URI_MAX_LENGTH = 4095 };
00530 char *p, *fn, *pi, *cp = NULL;
00531 size_t uri_len = strlen(uri);
00532
00533 dbg_err_if (rq == NULL);
00534 dbg_err_if (uri == NULL);
00535
00536
00537
00538 request_clear_uri(rq);
00539
00540
00541
00542 warn_err_ifm(uri_len > REQUEST_URI_MAX_LENGTH, "Request URI too long");
00543
00544 REQUEST_SET_STRING_FIELD(rq->uri, uri);
00545
00546
00547 if((p = strchr(uri, '?')) != NULL)
00548 dbg_err_if(request_set_query_string(rq, ++p));
00549
00550 cp = (char*)u_malloc(uri_len + 1);
00551 dbg_err_if(cp == NULL);
00552
00553
00554 dbg_err_if(u_urlncpy(cp, rq->uri, uri_len, URLCPY_DECODE) <= 0);
00555
00556 if((p = strchr(cp, '?')) != NULL)
00557 *p++ = 0;
00558
00559
00560 dbg_err_if(request_set_filename(rq, cp));
00561
00562
00563 fn = cp;
00564 pi = fn + strlen(fn);
00565 for(;;)
00566 {
00567 if(is_valid_uri == NULL || is_valid_uri(arg, fn, pi - fn))
00568 {
00569 dbg_err_if(request_set_filename(rq, fn));
00570 rq->filename[pi-fn] = 0;
00571 if(strlen(pi))
00572 dbg_err_if(request_set_path_info(rq, pi));
00573 break;
00574 } else {
00575 if((p = u_strnrchr(fn, '/', pi - fn)) == NULL)
00576 break;
00577 pi = p;
00578 }
00579 }
00580
00581 U_FREE(cp);
00582
00583 return 0;
00584 err:
00585 U_FREE(cp);
00586 return ~0;
00587 }
00588
00589 static int request_set_proto(request_t *rq, const char *proto)
00590 {
00591 dbg_err_if (rq == NULL);
00592 dbg_err_if (proto == NULL);
00593
00594
00595 if(strncasecmp(proto, "http", 4))
00596 return ~0;
00597
00598 REQUEST_SET_STRING_FIELD(rq->protocol, proto);
00599
00600 return 0;
00601 err:
00602 return ~0;
00603 }
00604
00615 int request_set_method(request_t *rq, const char *method)
00616 {
00617 dbg_return_if (rq == NULL, ~0);
00618 dbg_return_if (method == NULL, ~0);
00619
00620 if(!strcasecmp(method, "get"))
00621 rq->method = HM_GET;
00622 else if(!strcasecmp(method, "head"))
00623 rq->method = HM_HEAD;
00624 else if(!strcasecmp(method, "post"))
00625 rq->method = HM_POST;
00626 else {
00627
00628 rq->method = HM_UNKNOWN;
00629 return ~0;
00630 }
00631
00632 return 0;
00633 }
00634
00635 static int request_set_content_length(request_t *rq)
00636 {
00637 const char *clen;
00638 size_t len;
00639
00640 dbg_err_if (rq == NULL);
00641
00642 clen = header_get_field_value(rq->header, "Content-Length");
00643 dbg_err_if(clen == NULL || (len = atoi(clen)) < 0);
00644
00645 rq->content_length = len;
00646
00647 return 0;
00648 err:
00649 return ~0;
00650 }
00651
00652 static int request_parse_cookie(request_t *rq, field_t *field)
00653 {
00654 enum { BUFSZ = 4096 };
00655 char *pp, *tok, *src, buf[BUFSZ];
00656
00657 dbg_err_if (rq == NULL);
00658 dbg_err_if (field == NULL);
00659
00660 dbg_err_if(field_get_value(field) == NULL);
00661
00662
00663 strncpy(buf, field_get_value(field), BUFSZ);
00664
00665
00666 for(src = buf; (tok = strtok_r(src, " ;", &pp)) != NULL; src = NULL)
00667 dbg_if(vars_add_urlvar(rq->cookies, tok, NULL));
00668
00669 return 0;
00670 err:
00671 return ~0;
00672 }
00673
00674 static int request_parse_cookies(request_t *rq)
00675 {
00676 field_t *f;
00677 size_t i, count;
00678
00679 dbg_err_if (rq == NULL);
00680
00681 count = header_field_count(rq->header);
00682 for(i = 0; i < count; ++i)
00683 {
00684 f = header_get_fieldn(rq->header, i);
00685 dbg_err_if(f == NULL);
00686 if(strcasecmp(field_get_name(f), "cookie") == 0)
00687 dbg_err_if(request_parse_cookie(rq, f));
00688 }
00689
00690 return 0;
00691 err:
00692 return ~0;
00693 }
00694
00695 static int request_parse_query_args(request_t *rq)
00696 {
00697 char *pp, *tok, *src, *query = NULL;
00698
00699 dbg_err_if (rq == NULL);
00700
00701 if(!rq->query)
00702 return 0;
00703
00704
00705 query = u_strdup(rq->query);
00706 dbg_err_if(query == NULL);
00707
00708
00709 for(src = query; (tok = strtok_r(src, "&", &pp)) != NULL; src = NULL)
00710 {
00711
00712 dbg_if(vars_add_urlvar(rq->args, tok, NULL));
00713 }
00714
00715 U_FREE(query);
00716
00717 return 0;
00718 err:
00719 U_FREE(query);
00720 return ~0;
00721 }
00722
00723
00724 void request_set_cgi(request_t *rq, int cgi)
00725 {
00726 rq->cgi = cgi;
00727 return;
00728 }
00729
00740 ssize_t request_get_content_length(request_t *rq)
00741 {
00742 dbg_return_if (rq == NULL, -1);
00743
00744 return (ssize_t) rq->content_length;
00745 }
00746
00747 static int match_content_type(header_t *h, const char *mime_type)
00748 {
00749 const char *ct;
00750
00751 dbg_return_if (h == NULL, 0);
00752 dbg_return_if (mime_type == NULL, 0);
00753
00754 ct = header_get_field_value(h, "Content-Type");
00755 if(ct == NULL || strncasecmp(ct, mime_type, strlen(mime_type)))
00756 return 0;
00757
00758 return 1;
00759 }
00760
00761 static int request_is_multipart_formdata(request_t *rq)
00762 {
00763 return match_content_type(rq->header, "multipart/form-data");
00764 }
00765
00766 static int request_parse_urlencoded_data(request_t *rq)
00767 {
00768 ssize_t qsz, len;
00769
00770 dbg_err_if (rq == NULL);
00771
00772 len = rq->content_length;
00773
00774 qsz = (rq->query ? strlen(rq->query) : 0);
00775
00776
00777 rq->query = u_realloc(rq->query, len + qsz + 2);
00778 dbg_err_if(rq->query == NULL);
00779
00780
00781
00782 rq->query[qsz] = 0;
00783 if(qsz)
00784 {
00785 strcat(rq->query, "&");
00786 ++qsz;
00787 }
00788
00789
00790 dbg_err_if(io_read(rq->io, rq->query + qsz, len) != len);
00791
00792
00793 rq->query[qsz + len] = 0;
00794
00795
00796 dbg_err_if(request_parse_query_args(rq));
00797
00798 return 0;
00799 err:
00800 return ~0;
00801 }
00802
00803
00804
00805 static int request_get_fieldparam(request_t *rq, const char *field_name,
00806 const char *param_name, char *buf, size_t size)
00807 {
00808 const char *param_value, *field_value, *p;
00809 size_t pv_len;
00810
00811 dbg_err_if (rq == NULL);
00812 dbg_err_if (field_name == NULL);
00813 dbg_err_if (param_name == NULL);
00814 dbg_err_if (buf == NULL);
00815 dbg_err_if (size == 0);
00816
00817 field_value = header_get_field_value(rq->header, field_name);
00818 dbg_err_if(field_value == NULL);
00819
00820
00821 param_value = u_stristr(field_value, param_name);
00822 dbg_err_if(param_value == NULL);
00823
00824
00825 param_value += strlen(param_name);
00826
00827
00828 dbg_err_if(*param_value++ != '=');
00829
00830
00831 for(p = param_value; ;++p)
00832 if(*p == '\0' || *p == ';' || isspace(*p))
00833 break;
00834
00835
00836 pv_len = p - param_value;
00837
00838
00839 dbg_err_if(pv_len > size - 1);
00840
00841
00842 strncpy(buf, param_value, pv_len);
00843 buf[MIN(pv_len, size - 1)] = 0;
00844
00845 return 0;
00846 err:
00847 return ~0;
00848 }
00849
00850 static int is_multipart_mixed(header_t *h)
00851 {
00852 return match_content_type(h, "multipart/mixed");
00853 }
00854
00855 static int is_encoded(header_t *h)
00856 {
00857 const char *cte;
00858
00859 dbg_return_if (h == NULL, 0);
00860
00861 if((cte = header_get_field_value(h, "Content-Transfer-Encoding")) == NULL)
00862 return 0;
00863
00864 if(strcasecmp(cte, "binary") == 0)
00865 return 0;
00866
00867 return 1;
00868 }
00869
00870 static inline int is_nl(char c)
00871 {
00872 return (c == '\n' || c == '\r' ? c : 0);
00873 }
00874
00875 static inline int is_quote(char c)
00876 {
00877 return (c == '"' || c == '\'' ? c : 0);
00878 }
00879
00880 static int parse_content_disposition(header_t *h, char *name, char *filename,
00881 size_t prmsz)
00882 {
00883 enum { BUFSZ = 512 };
00884 char *pp, *tok, *src, buf[BUFSZ];
00885 size_t n_len, fn_len;
00886 const char *cd;
00887 int q;
00888
00889 dbg_err_if (h == NULL);
00890 dbg_err_if (name == NULL);
00891 dbg_err_if (filename == NULL);
00892 dbg_err_if (prmsz == 0);
00893
00894 cd = header_get_field_value(h, "Content-Disposition");
00895 dbg_err_if(cd == NULL);
00896
00897 dbg_err_if(strlen(cd) >= BUFSZ);
00898
00899
00900 dbg_err_if(strncmp(cd, "form-data", strlen("form-data")));
00901
00902 name[0] = filename[0] = 0;
00903
00904
00905 strncpy(buf, cd, BUFSZ);
00906
00907
00908 n_len = strlen("name=");
00909 fn_len = strlen("filename=");
00910
00911
00912 for(src = buf; (tok = strtok_r(src, " ;", &pp)) != NULL; src = NULL)
00913 {
00914 if(strncmp(tok, "form-data", strlen("form-data")) == 0)
00915 continue;
00916 else if(strncmp(tok, "name=", n_len) == 0) {
00917
00918 tok += n_len;
00919
00920
00921 if((q = is_quote(tok[0])) != 0)
00922 ++tok;
00923 if(strlen(tok) && tok[strlen(tok) - 1] == q)
00924 tok[strlen(tok) - 1] = 0;
00925
00926 strncpy(name, tok, prmsz);
00927 } else if(strncmp(tok, "filename=", fn_len) == 0) {
00928
00929 tok += fn_len;
00930
00931
00932 if((q = is_quote(tok[0])) != 0)
00933 ++tok;
00934 if(strlen(tok) && tok[strlen(tok) - 1] == q)
00935 tok[strlen(tok) - 1] = 0;
00936
00937 strncpy(filename, tok, prmsz);
00938 }
00939
00940 }
00941
00942 return 0;
00943 err:
00944 return ~0;
00945 }
00946
00947
00948
00949
00950
00951
00952
00953
00954 static ssize_t read_until(io_t *io, const char *stop_at, char *obuf,
00955 size_t size, int *found)
00956 {
00957
00958
00959
00960 #define SETUP_BUF_ACCESS_AT(idx) \
00961 if(idx >= wtot) { \
00962 if(idx >= size) \
00963 return wtot; \
00964 \
00965 \
00966 dbg_err_if((rc = io_read(io, wbuf, idx + 1 - wtot)) < 0); \
00967 if(rc == 0 || rc < idx + 1 - wtot) \
00968 return wtot + rc; \
00969 wbuf += rc; \
00970 wtot += rc; \
00971 }
00972
00973 int sa_len = strlen(stop_at);
00974 int i, t, shift[256], rc;
00975 unsigned char c;
00976 size_t wtot = 0;
00977 char *wbuf = obuf;
00978
00979 dbg_err_if (io == NULL);
00980 dbg_err_if (stop_at == NULL);
00981 dbg_err_if (obuf == NULL);
00982
00983 dbg_err_if (found == NULL);
00984
00985 for(i = 0; i < 256; ++i)
00986 shift[i] = sa_len;
00987
00988 for(i = 0; i < sa_len; ++i)
00989 shift[ stop_at[i] ] = sa_len - i - 1;
00990
00991 *found = 0;
00992
00993 for(i = t = sa_len-1; t >= 0; --i, --t)
00994 {
00995 SETUP_BUF_ACCESS_AT(i);
00996
00997 while((c = obuf[i]) != stop_at[t])
00998 {
00999 i += MAX(sa_len - t, shift[c]);
01000
01001 SETUP_BUF_ACCESS_AT(i);
01002
01003 t = sa_len - 1;
01004 }
01005 }
01006
01007 *found = 1;
01008
01009
01010 return wtot;
01011 err:
01012 return -1;
01013 }
01014
01015
01033 vars_t *request_get_uploads(request_t *rq)
01034 {
01035 return rq->uploads;
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045 static int request_add_uploaded_file(request_t *rq, const char *name,
01046 const char *filename, const char *tmp_filename, const char *mime_type)
01047 {
01048 struct stat st;
01049 var_t *v = NULL;
01050 upload_info_t *info = NULL;
01051
01052 dbg_err_if (rq == NULL);
01053 dbg_err_if (name == NULL);
01054
01055 dbg_err_if (tmp_filename == NULL);
01056
01057
01058 dbg_err_sif (stat(tmp_filename, &st) < 0);
01059
01060
01061 dbg_err_if(var_create(name, tmp_filename, &v));
01062
01063
01064 dbg_err_if((info = u_zalloc(sizeof(upload_info_t))) == NULL);
01065
01066
01067 info->size = st.st_size;
01068 if(mime_type)
01069 snprintf(info->mime_type, MIME_TYPE_BUFSZ, "%s", mime_type);
01070 else
01071 info->mime_type[0] = 0;
01072
01073 if(filename)
01074 snprintf(info->filename, U_FILENAME_MAX, "%s", filename);
01075
01076
01077 var_set_opaque(v, info);
01078 info = NULL;
01079
01080
01081 dbg_err_if(vars_add(rq->uploads, v));
01082
01083 return 0;
01084 err:
01085 if(info)
01086 U_FREE(info);
01087 if(v)
01088 var_free(v);
01089 return ~0;
01090 }
01091
01092
01093
01094 int request_get_uploaded_filev(request_t *rq, var_t *v,
01095 char local_filename[U_FILENAME_MAX], char client_filename[U_FILENAME_MAX],
01096 char mime_type[MIME_TYPE_BUFSZ], size_t *file_size)
01097 {
01098 upload_info_t *info;
01099 const char *tmp_fqn;
01100
01101 dbg_err_if (rq == NULL);
01102 dbg_err_if (v == NULL);
01103 dbg_err_if (local_filename == NULL);
01104 dbg_err_if (client_filename == NULL);
01105 dbg_err_if (mime_type == NULL);
01106 dbg_err_if (file_size == NULL);
01107
01108 info = var_get_opaque(v);
01109 dbg_err_if(info == NULL);
01110
01111 tmp_fqn = var_get_value(v);
01112 dbg_err_if(tmp_fqn == NULL);
01113
01114
01115 strncpy(local_filename, tmp_fqn, U_FILENAME_MAX);
01116 strncpy(mime_type, info->mime_type, MIME_TYPE_BUFSZ);
01117 strncpy(client_filename, info->filename, U_FILENAME_MAX);
01118 *file_size = info->size;
01119
01120 return 0;
01121 err:
01122 return ~0;
01123 }
01124
01146 int request_get_uploaded_file(request_t *rq, const char *name, size_t idx,
01147 char local_filename[U_FILENAME_MAX], char client_filename[U_FILENAME_MAX],
01148 char mime_type[MIME_TYPE_BUFSZ], size_t *file_size)
01149 {
01150 var_t *v;
01151 upload_info_t *info;
01152 const char *tmp_fqn;
01153
01154 dbg_err_if (rq == NULL);
01155 dbg_err_if (name == NULL);
01156 dbg_err_if (idx >= vars_count(rq->uploads));
01157 dbg_err_if (local_filename == NULL);
01158 dbg_err_if (client_filename == NULL);
01159 dbg_err_if (mime_type == NULL);
01160 dbg_err_if (file_size == NULL);
01161
01162 v = vars_geti(rq->uploads, name, idx);
01163 dbg_err_if(v == NULL);
01164
01165 return request_get_uploaded_filev(rq, v, local_filename, client_filename,
01166 mime_type, file_size);
01167 err:
01168 return ~0;
01169 }
01170
01171 static int request_parse_multipart_chunk(request_t *rq, io_t *io,
01172 const char *boundary, int *eof)
01173 {
01174 enum { PRMSZ = 512, BUFSZ = 4096 };
01175 header_t *h = NULL;
01176 io_t *tmpio = NULL;
01177 var_t *v = NULL;
01178 char name[PRMSZ], filename[PRMSZ], buf[BUFSZ];
01179 size_t bound_len, len;
01180 int found;
01181 ssize_t rc;
01182
01183
01184 dbg_err_if(header_create(&h));
01185
01186
01187 dbg_err_if(header_load(h, io));
01188
01189 warn_err_ifm(is_multipart_mixed(h),
01190 "multipart/mixed content is not supported yet");
01191
01192
01193 warn_err_ifm(is_encoded(h),
01194 "encoded file upload is not supported");
01195
01196 dbg_err_if(parse_content_disposition(h, name, filename, PRMSZ));
01197
01198
01199 bound_len = strlen(boundary);
01200
01201 if(filename[0] != '\0')
01202 {
01203 dbg_err_if(BUFSZ <= bound_len);
01204
01205
01206 dbg_err_if(u_tmpfile_open(&tmpio));
01207
01208 for(found = 0; !found; )
01209 {
01210 rc = read_until(io, boundary, buf, BUFSZ, &found);
01211 dbg_err_if(rc <= 0);
01212
01213
01214 if(found)
01215 {
01216 rc -= (bound_len + 2);
01217 dbg_err_if(rc < 0);
01218 }
01219
01220
01221 dbg_err_if(io_write(tmpio, buf, rc) < 0);
01222 }
01223
01224
01225 dbg_err_if(io_name_get(tmpio, buf, BUFSZ));
01226
01227
01228 io_free(tmpio); tmpio = NULL;
01229
01230
01231 dbg_err_if(request_add_uploaded_file(rq, name, filename, buf,
01232 header_get_field_value(h, "Content-Type")));
01233
01234
01235 dbg_err_if(io_gets(io, buf, BUFSZ) <= 0);
01236
01237 if(strncmp(buf, "--", 2) == 0)
01238 *eof = 1;
01239
01240 } else {
01241
01242 rc = read_until(io, boundary, buf, BUFSZ, &found);
01243 dbg_err_if(rc <= 0);
01244
01245
01246 warn_err_ifm(!found, "malformed request or BUFSZ too small");
01247
01248 rc -= (bound_len + 2);
01249 dbg_err_if(rc < 0);
01250
01251
01252 buf[rc] = 0;
01253
01254
01255 dbg_err_if(var_bin_create(name, buf, rc, &v));
01256 dbg_if(vars_add(rq->args, v));
01257
01258
01259 dbg_err_if(io_gets(io, buf, BUFSZ) <= 0);
01260
01261 if(strncmp(buf, "--", 2) == 0)
01262 *eof = 1;
01263 }
01264
01265 header_free(h);
01266
01267 return 0;
01268 err:
01269 if(tmpio)
01270 io_free(tmpio);
01271 if(h)
01272 header_free(h);
01273 return ~0;
01274 }
01275
01276 static int request_parse_multipart_data(request_t *rq)
01277 {
01278 enum { BOUNDARY_BUFSZ = 128, BUFSZ = 1024 };
01279 char boundary[BOUNDARY_BUFSZ], buf[BUFSZ];
01280 int eof;
01281
01282
01283 strcpy(boundary, "--");
01284
01285 dbg_err_if(request_get_fieldparam(rq, "Content-Type", "boundary",
01286 boundary + 2, BOUNDARY_BUFSZ - 2));
01287
01288 dbg_err_if(strlen(boundary) == 0);
01289
01290
01291 for(;;)
01292 {
01293 dbg_err_if(io_gets(rq->io, buf, BUFSZ) <= 0);
01294 if(!strncmp(buf, boundary, strlen(boundary)))
01295 break;
01296 }
01297
01298
01299 for(eof = 0; eof == 0; )
01300 dbg_err_if(request_parse_multipart_chunk(rq, rq->io, boundary, &eof));
01301
01302 return 0;
01303 err:
01304 return ~0;
01305 }
01306
01307 static int request_cb_close_socket(talarm_t *al, void *arg)
01308 {
01309 io_t *io = (io_t*)arg;
01310
01311 u_unused_args(al);
01312
01313 warn("[%x] connection timed out, closing", io);
01314
01315
01316
01317 io->term(io);
01318
01319 return 0;
01320 }
01321
01322 int request_parse_data(request_t *rq)
01323 {
01324 talarm_t *al = NULL;
01325 int rc = HTTP_STATUS_BAD_REQUEST;
01326
01327 if(rq->method == HM_POST)
01328 {
01329
01330 dbg_err_if(timerm_add(rq->post_timeout, request_cb_close_socket,
01331 (void*)rq->io, &al));
01332
01333
01334 dbg_err_if(request_set_content_length(rq) &&
01335 (rc = HTTP_STATUS_LENGTH_REQUIRED));
01336
01337 if(rq->content_length == 0)
01338 return 0;
01339
01340
01341 dbg_err_if(rq->content_length > rq->post_maxsize &&
01342 (rc = HTTP_STATUS_REQUEST_TOO_LARGE));
01343
01344 if(request_is_multipart_formdata(rq))
01345 {
01346
01347 dbg_err_if(request_parse_query_args(rq));
01348
01349
01350 dbg_err_if(request_parse_multipart_data(rq));
01351 } else {
01352
01353 dbg_err_if(request_parse_urlencoded_data(rq));
01354 }
01355
01356
01357 dbg_if(timerm_del(al)); al = NULL;
01358 } else {
01359
01360 dbg_err_if(request_parse_query_args(rq));
01361 }
01362
01363 return 0;
01364 err:
01365 return rc;
01366 }
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379 int request_parse_header(request_t *rq,
01380 int (*is_valid_uri)(void*, const char *, size_t),
01381 void* arg)
01382 {
01383 enum { BUFSZ = 4096 };
01384 const char WP[] = " \t\r\n";
01385 char ln[BUFSZ], *pp, *method, *uri, *proto;
01386 talarm_t *al = NULL;
01387 int rc = HTTP_STATUS_BAD_REQUEST;
01388
01389 dbg_err_if (rq == NULL);
01390 dbg_err_if (rq->io == NULL);
01391
01392
01393 dbg_err_if(timerm_add(rq->idle_timeout, request_cb_close_socket,
01394 (void*)rq->io, &al));
01395
01396 if(!rq->cgi)
01397 {
01398
01399 dbg_err_if(io_gets(rq->io, ln, BUFSZ) <= 0);
01400
01401 method = strtok_r(ln, WP, &pp);
01402 dbg_err_if(!method || request_set_method(rq, method));
01403
01404 uri = strtok_r(NULL, WP, &pp);
01405 dbg_err_if(!uri || request_set_uri(rq, uri, is_valid_uri, arg));
01406
01407
01408 proto = strtok_r(NULL, WP, &pp);
01409 dbg_err_if(!proto || request_set_proto(rq, proto));
01410
01411 dbg_err_if(header_load(rq->header, rq->io));
01412 } else
01413 dbg_err_if(header_load_from_cgienv(rq->header));
01414
01415
01416 dbg_err_if(request_parse_ims(rq));
01417
01418
01419 dbg_err_if(request_parse_cookies(rq));
01420
01421
01422 dbg_if(timerm_del(al)); al = NULL;
01423
01424
01425 dbg_err_if((rc = request_parse_data(rq)));
01426
01427 return 0;
01428 err:
01429 return rc;
01430 }
01431
01442 int request_get_method(request_t *rq)
01443 {
01444 dbg_return_if (rq == NULL, HM_UNKNOWN);
01445
01446 return rq->method;
01447 }
01448
01458 const char *request_get_resolved_filename(request_t *rq)
01459 {
01460 dbg_return_if (rq == NULL, NULL);
01461
01462 return rq->resolved_filename;
01463 }
01464
01474 const char *request_get_resolved_path_info(request_t *rq)
01475 {
01476 dbg_return_if (rq == NULL, NULL);
01477
01478 return rq->resolved_path_info;
01479 }
01480
01481 int request_print(request_t *rq)
01482 {
01483 dbg_return_if (rq == NULL, ~0);
01484
01485 dbg("method: %u", rq->method);
01486 dbg("uri: %s", rq->uri);
01487 dbg("proto: %s", rq->protocol);
01488 dbg("filename: %s", rq->filename);
01489 dbg("resolved filename: %s", rq->resolved_filename);
01490 dbg("path_info: %s", rq->path_info);
01491 dbg("resolved path_info: %s", rq->resolved_path_info);
01492 dbg("query: %s", rq->query);
01493
01494 return 0;
01495 }
01496
01497 static int request_load_config(request_t *rq)
01498 {
01499 u_config_t *c;
01500 const char *v;
01501
01502 dbg_err_if (rq == NULL);
01503 dbg_err_if (rq->http == NULL);
01504 dbg_err_if (http_get_config(rq->http) == NULL);
01505
01506 c = http_get_config(rq->http);
01507
01508
01509 rq->idle_timeout = REQUEST_DEFAULT_IDLE_TIMEOUT;
01510 rq->post_timeout = REQUEST_DEFAULT_POST_TIMEOUT;
01511 rq->post_maxsize = REQUEST_DEFAULT_POST_MAXSIZE;
01512
01513
01514 if((v = u_config_get_subkey_value(c, "idle_timeout")) != NULL)
01515 rq->idle_timeout = MAX(1, atoi(v));
01516
01517
01518 if((v = u_config_get_subkey_value(c, "post_timeout")) != NULL)
01519 rq->post_timeout = MAX(5, atoi(v));
01520
01521
01522 if((v = u_config_get_subkey_value(c, "post_maxsize")) != NULL)
01523 rq->post_maxsize = MAX(1024, atoi(v));
01524
01525 return 0;
01526 err:
01527 return ~0;
01528 }
01529
01530 int request_create(http_t *http, request_t **prq)
01531 {
01532 request_t *rq = NULL;
01533
01534 dbg_return_if (prq == NULL, ~0);
01535 dbg_return_if (http == NULL, ~0);
01536
01537 rq = u_zalloc(sizeof(request_t));
01538 dbg_err_if(rq == NULL);
01539
01540 dbg_err_if(header_create(&rq->header));
01541
01542 dbg_err_if(vars_create(&rq->args));
01543 dbg_err_if(vars_create(&rq->cookies));
01544 dbg_err_if(vars_create(&rq->uploads));
01545
01546 rq->http = http;
01547
01548 dbg_err_if(request_load_config(rq));
01549
01550 *prq = rq;
01551
01552 return 0;
01553 err:
01554 if(rq)
01555 request_free(rq);
01556 return ~0;
01557 }
01558
01559 static int request_unlink_uploads(var_t *v, void * arg)
01560 {
01561 dbg_err_if (v == NULL);
01562
01563 u_unused_args(arg);
01564
01565 if(var_get_opaque(v) && var_get_value(v))
01566 {
01567 unlink(var_get_value(v));
01568 }
01569
01570 err:
01571 return 0;
01572 }
01573
01574 int request_free(request_t *rq)
01575 {
01576 if (rq)
01577 {
01578
01579 request_clear_uri(rq);
01580
01581 if(rq->header)
01582 header_free(rq->header);
01583
01584 if(rq->io)
01585 io_free(rq->io);
01586
01587 if(rq->uploads)
01588 {
01589
01590 vars_foreach(rq->uploads, request_unlink_uploads, NULL);
01591 vars_free(rq->uploads);
01592 }
01593
01594 if(rq->cookies)
01595 vars_free(rq->cookies);
01596
01597 if(rq->args)
01598 vars_free(rq->args);
01599
01600 U_FREE(rq);
01601 }
01602
01603 return 0;
01604 }
01605
01606
01607 int request_set_addr(request_t *rq, addr_t *addr)
01608 {
01609 dbg_return_if (rq == NULL, ~0);
01610 dbg_return_if (addr == NULL, ~0);
01611
01612 memcpy(&rq->local_addr, addr, sizeof(addr_t));
01613
01614 return 0;
01615 }
01616
01617
01618 int request_set_peer_addr(request_t *rq, addr_t *addr)
01619 {
01620 dbg_return_if (rq == NULL, ~0);
01621 dbg_return_if (addr == NULL, ~0);
01622
01623 memcpy(&rq->peer_addr, addr, sizeof(addr_t));
01624
01625 return 0;
01626 }
01627
01628
01629 addr_t* request_get_addr(request_t *rq)
01630 {
01631 dbg_return_if (rq == NULL, NULL);
01632
01633 return &rq->local_addr;
01634 }
01635
01636
01637 addr_t* request_get_peer_addr(request_t *rq)
01638 {
01639 dbg_return_if (rq == NULL, NULL);
01640
01641 return &rq->peer_addr;
01642 }
01643
01644
01645 header_t* request_get_header(request_t *rq)
01646 {
01647 dbg_return_if (rq == NULL, NULL);
01648
01649 return rq->header;
01650 }
01651
01652
01653
01654 field_t* request_get_field(request_t *rq, const char *name)
01655 {
01656 dbg_return_if (rq == NULL, NULL);
01657 dbg_return_if (name == NULL, NULL);
01658
01659 return header_get_field(rq->header, name);
01660 }
01661
01662
01663
01664 const char* request_get_field_value(request_t *rq, const char *name)
01665 {
01666 dbg_return_if (rq == NULL, NULL);
01667 dbg_return_if (name == NULL, NULL);
01668
01669 return header_get_field_value(rq->header, name);
01670 }
01671
01672