457 lines
14 KiB
C++
457 lines
14 KiB
C++
/*
|
|
* This file is a part of Winix
|
|
* and is distributed under the 2-Clause BSD licence.
|
|
* Author: Tomasz Sowa <t.sowa@ttmath.org>
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2008-2018, 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 <fcgiapp.h>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include "requesttypes.h"
|
|
#include "item.h"
|
|
#include "error.h"
|
|
#include "config.h"
|
|
#include "textstream.h"
|
|
#include "templates/htmltextstream.h"
|
|
#include "date/date.h"
|
|
#include "space/space.h"
|
|
#include "space/spacetojson.h"
|
|
#include "textstream/textstream.h"
|
|
#include "outstreams.h"
|
|
|
|
|
|
namespace Winix
|
|
{
|
|
|
|
|
|
|
|
|
|
class FunctionBase;
|
|
|
|
|
|
|
|
|
|
struct Request
|
|
{
|
|
// 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;
|
|
|
|
|
|
/*
|
|
request input variables representing the winix filesystem
|
|
*/
|
|
|
|
// current directory
|
|
std::vector<Item*> 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<HtmlTextStream> 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;
|
|
|
|
// info serializer
|
|
// if not set then the json_generic_serializer from App will be used
|
|
// default: null (json_generic_serializer used)
|
|
PT::SpaceToJSON * info_serializer;
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
|
|
/*
|
|
additional variables used for common uses
|
|
*/
|
|
|
|
// usually items in the current directory (depends on the function)
|
|
std::vector<Item> item_tab;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Request();
|
|
void SetConfig(Config * pconfig);
|
|
|
|
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<typename NameType, typename ValueType>
|
|
std::wstring & AddCookie(const NameType & name, const ValueType & value, PT::Date * expires = 0);
|
|
|
|
template<typename NameType, typename ValueType>
|
|
std::wstring & 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<typename NameType, typename ValueType>
|
|
std::wstring & 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)
|
|
*/
|
|
|
|
return out_cookies.Add(name, cookie);
|
|
}
|
|
|
|
|
|
template<typename NameType, typename ValueType>
|
|
std::wstring & Request::AddCookie(const NameType & name, const ValueType & value, PT::Date & expires)
|
|
{
|
|
return AddCookie(name, value, &expires);
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Winix
|
|
|
|
#endif
|
|
|