/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2008-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #ifndef headerfile_winix_core_request #define headerfile_winix_core_request #include #include #include #include "requesttypes.h" #include "models/item.h" #include "error.h" #include "config.h" #include "textstream.h" #include "templates/htmltextstream.h" #include "date/date.h" #include "space/space.h" #include "textstream/textstream.h" #include "outstreams.h" #include "models.h" #include "models/winixmodel.h" namespace Winix { class FunctionBase; struct Request : public WinixModel { // how many input headers can be put to in_headers struct static const size_t MAX_INPUT_HEADERS = 32; // how many characters there can be in one header name static const size_t INPUT_HEADER_NAME_MAX_LENGTH = 64; // how many characters there can be in one header value static const size_t INPUT_HEADER_VALUE_MAX_LENGTH = 8192; /* request id is incremented for each request and is never 0 (from -1 will be incremented to one) it's used for some optimizations e.g. in templates */ size_t id; /* request start time Time() methods are very slow so it is better to directly use those two values they are set when a request starts */ time_t start_time; pt::Date start_date; /* * * * * variables representing input from client's browser * * * */ /* the HTTP method !! IMPROVE ME add the rest methods here */ enum Method { get, post, head, delete_, unknown_method } method; /* subdomain subdomain = HTTP_HOST environment variable - config->base_url */ std::wstring subdomain; /* raw parameters !! CHECK ME may post_tab and cookie_tab should be changed to pt::Space now? or may change the name to cookie_in? or in_cookie? */ PostTab post_tab; PostFileTab post_file_tab; CookieTab cookie_tab; pt::Space post_in; bool is_postin_used;// temporarily, before all post variables will be put to post_in // input headers (without cookies) // at the moment we are using FastCGI and HTTP headers are prefixed with 'HTTP_' string // so we drop the prefix and change all characters to small ones // although https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 says that there can be more // than one http header with the same name we do not support it // each header has a different name here, cookies we have in a different container (cookie_tab) pt::Space headers_in; /* html anchor (those part of URI after '#' character) */ std::wstring anchor; // environment variables std::wstring env_request_method; std::wstring env_request_uri; std::wstring env_http_cookie; std::wstring env_http_host; std::wstring env_http_user_agent; std::wstring env_http_accept_encoding; std::wstring env_fcgi_role; std::wstring env_content_type; std::wstring env_https; // current IP address of the remote host // (read either from REMOTE_ADDR environment variable or from config.proxy_ip_header HTTP variable if config.check_proxy_ip_header is set to true) // (at the moment only IPv4 are supported) int ip; std::wstring ip_str; // ip_str can be ipv6 now // true if the browser is Microsoft Internet Explorer bool browser_msie; // true if the browser is Konqueror bool browser_konqueror; // true if we are using an encrypted connection (SSL) bool using_ssl; // true if the request is being made by ajax by htmx library bool is_htmx_request; /* request input variables representing the winix filesystem */ // current directory std::vector dir_tab; // true if a file exists bool is_item; // current file (valid if is_item is true) Item item; // current winix function // null if there is no a function FunctionBase * function; // parameters (name:value) ParamTab param_tab; // this is a pointer either to the item (if exists) or to the last directory Item * last_item; /* * * * * variables for generating output to the client's browser * * * */ // request status // !! CHANGE ME it'll be better to use ordinary http result codes Error status; // if not empty means an address for redirecting to // it should be url-encoded std::wstring redirect_to; // a redirect type // following redirect types are supported: // 300 Multiple Choices // 301 Moved Permanently // 302 Found // 303 See Other (default) // 307 Temporary Redirect int redirect_type; // send header X-LIGHTTPD-send-file with path to a file std::wstring x_sendfile; // send as attachment (causes generating header: content-disposition: attachment) bool send_as_attachment; // headers send to the client (without cookies) (may change to headers_out?) pt::Space out_headers; // cookies send to the client // a value can be either a cookie value or the whole cookie string (with domain, date etc) pt::Space out_cookies; // winix can return either a text answer or a binary answer // if send_bin_stream is true then the binary answer is sent (out_bin_stream) // or if send_bin_stream is false then the text answer is sent // default: false // // // winix answer send to the client's browser // | // | // depending on send_bin_stream // (if false) ------------------------------------------------- (if true) // | | // text answer binary answer // | | // depending on return_json sending out_bin_stream // (if false) ------------------------------------ (if true) // | | // normal request ajax request // | | // sending out_main_stream | // | // | // depending on return_info_only // (if false) ------------------------------------------------------------- (if true) // | | // generating JSON object from: generating JSON object only from info // out_streams and info, e.g.: e.g.: // { { info object serialized here } // "out": { out_streams serialized here e.g.: // "stream_name_1": "some html content", // "stream_name_2": "some other html content" // }, // "info": { info object serialized here } // } // // bool send_bin_stream; // binary page sent to the client if send_bin_stream is true BinaryPage out_bin_stream; // when returning the text answer we can either return the whole html page (normal requests) // or a JSON object (for requests generated from AJAX) // if return_json is false then we return the whole html page (which is in out_main_stream) // if return_json is true we are creating an JSON object from out_streams // and from info space (see above picture) // (or just only from info if return_info_only is true) // default: false // return_json is set to true by App at the beginning of a request // if reqtype:json parameter is present (in the url) // note: return_json is only valid if send_bin_stream is false bool return_json; // main text output stream where the html otput is generated from ezc templates // here the whole html page (with doctype, head, body) is generated HtmlTextStream out_main_stream; // text output streams used in ajax requests (send in JSON format to the client) // in ezc templates you can use [ezc out "stream_name"] keyword // to switch between streams Ezc::OutStreams out_streams; // if true the JSON object is generated only from info (out_streams are not used) // default: false bool return_info_only; // additional info added when sending the JSON answer pt::Space info; // models to return or to render through ezc library Ezc::Models models; // if set to true then the standard template system will not be used // default: false bool page_generated; // whether or not the main html stream should be filtered by our html filter bool out_main_stream_use_html_filter; // whether or not the ajax streams should be filtered by our html filter // this filter is only aplied to streams in "out" space, "info" space is not touched bool out_streams_use_html_filter; // if this variable is true then winix always return 200 OK header // when the status would be 404 (not found) or 403 (permission denied) // default: false bool use_200_status_for_not_found_and_permission_denied; // options used by ezc generators bool gen_trim_white; bool gen_skip_new_line; bool gen_use_special_chars; // index template name std::wstring html_template; /* additional variables used for common uses */ // usually items in the current directory (depends on the function) std::vector item_tab; Request(); void SetConfig(Config * pconfig); void fields(); void RequestStarts(); void Clear(); bool IsParam(const wchar_t * param_name); bool IsParam(const std::wstring & param_name); const std::wstring & ParamValue(const wchar_t * param_name); // returns an empty string if there is no such a parameter const std::wstring & ParamValue(const std::wstring & param_name); // returns an empty string if there is no such a parameter std::wstring * ParamValuep(const wchar_t * param_name); // returns nullptr if there is no such a parameter std::wstring * ParamValuep(const std::wstring & param_name); // returns nullptr if there is no such a parameter bool IsPostVar(const wchar_t * var); bool IsPostVar(const std::wstring & var); const std::wstring & PostVar(const wchar_t * var); // returns an empty string if there is no such a parameter const std::wstring & PostVar(const std::wstring & var); // returns an empty string if there is no such a parameter bool PostVar(const wchar_t * var, std::wstring & result); bool PostVar(const std::wstring & var, std::wstring & result); std::wstring * PostVarp(const wchar_t * var); std::wstring * PostVarp(const std::wstring & var); bool AllPostVarEmpty(); // returning true if all post vars are empty // setting a cookie // name - cookie name (either const wchar_t, or std::wstring or pt::WTextStream) // value - cookie value (can be everything which can be put to pt::WTextStream stream) // the return std::wstring reference is a reference to the cookie inserted value (in out_cookies structure) template void AddCookie(const NameType & name, const ValueType & value, pt::Date * expires = 0); template void AddCookie(const NameType & name, const ValueType & value, pt::Date & expires); private: Config * config; // used in ParamValue() and PostVar() when there is no such a param const std::wstring str_empty; void ClearOutputStreams(); }; template void Request::AddCookie(const NameType & name, const ValueType & value, pt::Date * expires) { pt::WTextStream cookie; cookie << value; if( cookie.empty() ) cookie << L"\"\""; // cookie empty value if( expires ) cookie << L"; expires=" << DateToStrCookie(*expires) << L" GMT"; cookie << L"; path=/; domain=" << config->base_url; /* !! IMPROVE ME add an option to the config don't use '; secure' flag if you are using both sites (with SSL and without SSL) -- with secure flag the cookie is sent only through SSL and if you accidentally open a new window without SSL (http://) then winix will create a new session for you and the previous session (https://) will be lost (the session cookie will be overwritten in the client's browser) */ out_cookies.add_stream(name, cookie); } template void Request::AddCookie(const NameType & name, const ValueType & value, pt::Date & expires) { AddCookie(name, value, &expires); } } // namespace Winix #endif