File:  [parser3project] / parser3 / src / types / pa_vrequest.C
Revision 1.75: download - view: text, annotated - select for diffs - revision graph
Sat Apr 25 13:38:46 2026 UTC (6 weeks, 3 days ago) by moko
Branches: MAIN
CVS tags: HEAD
Copyright year updated, websites links changed to https://

/** @file
	Parser: @b request class.

	Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
	Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
*/

#include "pa_vrequest.h"
#include "pa_request_info.h"
#include "pa_request_charsets.h"
#include "pa_charsets.h"
#include "pa_vstring.h"
#include "pa_vhash.h"
#include "pa_vform.h"
#include "pa_vvoid.h"
#include "pa_vfile.h"

volatile const char * IDENT_PA_VREQUEST_C="$Id: pa_vrequest.C,v 1.75 2026/04/25 13:38:46 moko Exp $" IDENT_PA_VREQUEST_H;

// defines

#define DOCUMENT_ROOT_NAME "document-root"
#define REQUEST_HEADERS_ELEMENT_NAME "headers"

VRequest::VRequest(Request_info& ainfo, Request_charsets& acharsets, VForm& aform, SAPI_Info& asapi_info):
	finfo(ainfo),
	fsapi_info(asapi_info),
	fcharsets(acharsets),
	fform(aform)
{
	if(ainfo.argv)
		for(size_t i=0; ainfo.argv[i]; i++) {
			fargv.put_dont_replace(
				String(i, "%d"),
				new VString(pa_strdup(ainfo.argv[i]))
			);
		}
}

Value* VRequest::get_element(const String& aname) {
#ifndef OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL
	// $request:CLASS, $request:CLASS_NAME
	if(Value* result=VStateless_class::get_element(aname))
		return result;
#endif

	// $request:charset
	if(aname==CHARSET_NAME)
		return new VString(fcharsets.source().NAME());

	// $request:body-charset
	if(aname==REQUEST_BODY_CHARSET_NAME || aname==POST_CHARSET_NAME /*backward*/){
		if(Charset* body_charset=fform.get_body_charset())
			return new VString(body_charset->NAME());
		else
			return VVoid::get();
	}

	// $resuest:body-file
	if(aname==REQUEST_BODY_BODY_NAME || aname==POST_BODY_NAME /*backward*/){
		VFile& result=*new VFile;
		result.set_binary(true/*tainted*/, (finfo.post_data)?finfo.post_data:"" /*to distinguish from stat-ed file*/, finfo.post_size);
		return &result;
	}

	// $request:argv
	if(aname==REQUEST_ARGV_ELEMENT_NAME)
		return new VHash(fargv);
	
	//$request:headers
	if(aname==REQUEST_HEADERS_ELEMENT_NAME){
		if(!ffields.count())
			fill();
		return new VHash(ffields);
	}

	// $request:query $request:uri $request:document-root $request:body $request:method
	const char* buf;
	if(aname=="query")
		buf=finfo.query_string;
	else if(aname=="uri")
		buf=finfo.uri;
	else if(aname=="path")
		buf=path_from_uri(pa_strdup(finfo.uri));
	else if(aname==DOCUMENT_ROOT_NAME)
		buf=finfo.document_root;
	else if(aname=="body")
		buf=finfo.post_data;
	else if(aname=="method")
		buf=finfo.method;
	else
		return bark("%s field not found", &aname);

	return new VString(buf);
}

const VJunction* VRequest::put_element(const String& aname, Value* avalue) {
	// $charset
	if(aname==CHARSET_NAME) {
		fcharsets.set_source(pa_charsets.get(avalue->as_string()));
		return 0;
	} 

	// $document-root
	if(aname==DOCUMENT_ROOT_NAME) {
		finfo.document_root=avalue->as_string().taint_cstr(String::L_FILE_SPEC);
		return 0;
	} 

	return Value::put_element(aname, avalue);
}

void VRequest::fill(){
	for(SAPI::Env::Iterator i(fsapi_info); i; i.next() ){
		char* key=i.key();

		if(pa_strncasecmp(key, "HTTP_")==0) {
			for(char* c=key+5; *c; c++)
				*c=(char)toupper((unsigned char)*c);

			ffields.put(
				key+5 /*skip "HTTP_" */,
				new VString(i.value())
			);
		}
	}
}

const char* VRequest::path_from_uri(char* uri){
	const char *result=uri;
	lsplit(uri,'?');
	if(result && *result)
		result=unescape_chars(result, strlen(result), &pa_UTF8_charset, false /* uri */);
	if(result && *result)
		result=Charset::transcode(result, pa_UTF8_charset, fcharsets.source()).cstr();
	if(result && *result)
		return result;
	return ""; // to match an empty URI in console mode
}

E-mail: